diff options
author | Howard P. Logsdon <howard@hplogsdon.com> | 2015-04-24 11:45:17 -0600 |
---|---|---|
committer | Howard P. Logsdon <howard@hplogsdon.com> | 2015-04-30 22:02:28 -0600 |
commit | 4c63ef932bc2b573cd9306066993f72c1cb8dc83 (patch) | |
tree | 3b26f21873330db918237bd63c9a11404e2ec4e9 | |
parent | 3bbd2f55a299b31a702b7ae6aa2624e5116bc8e8 (diff) | |
download | gitlab-ci-4c63ef932bc2b573cd9306066993f72c1cb8dc83.tar.gz |
HipChat Notification Service
* Move existing Slack service spec into a subdir, mirroring /app
* Wire up HipChat service to the project and services controller.
* Split the message building into own class.
* 'namespace' room and token variables.
* Enforce v2 client (bug in HipChat gem v1.5.0. fixed in 1.5.1). Note
that I'm using the same version string as GitLab-CE, for shared
installations.
* Defer execution to a notifier worker, like the Slack service.
* Ensure passing specs (basically a Slack service spec copy, fwiw)
* Added change to the CHANGELOG
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | Gemfile | 3 | ||||
-rw-r--r-- | Gemfile.lock | 5 | ||||
-rw-r--r-- | app/controllers/services_controller.rb | 3 | ||||
-rw-r--r-- | app/models/project.rb | 3 | ||||
-rw-r--r-- | app/models/project_services/hip_chat_message.rb | 62 | ||||
-rw-r--r-- | app/models/project_services/hip_chat_service.rb | 67 | ||||
-rw-r--r-- | app/workers/hip_chat_notifier_worker.rb | 9 | ||||
-rw-r--r-- | spec/models/project_services/hip_chat_service_spec.rb | 48 | ||||
-rw-r--r-- | spec/models/project_services/slack_message_spec.rb (renamed from spec/models/slack_message_spec.rb) | 0 | ||||
-rw-r--r-- | spec/models/project_services/slack_service_spec.rb (renamed from spec/models/slack_service_spec.rb) | 0 |
11 files changed, 199 insertions, 2 deletions
@@ -4,6 +4,7 @@ v7.11.0 - Improved runners page - Running and Pending tabs on admin builds page - Fix [ci skip] tag, so you can skip CI triggering now + - Add HipChat notifications v7.10.1 - Fix failing migration when update to 7.10 from 7.8 and older versions @@ -63,6 +63,9 @@ gem "default_value_for", "~> 3.0.0" # Slack integration gem "slack-notifier", "~> 1.0.0" +# HipChat integration +gem 'hipchat', '~> 1.5.0' + # Other gem 'rake' gem 'foreman' diff --git a/Gemfile.lock b/Gemfile.lock index 41bc118..d2c9158 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -156,6 +156,9 @@ GEM hashie (2.0.5) highline (1.6.21) hike (1.2.3) + hipchat (1.5.0) + httparty + mimemagic httparty (0.11.0) multi_json (~> 1.0) multi_xml (>= 0.5.2) @@ -186,6 +189,7 @@ GEM mime-types (>= 1.16, < 3) method_source (0.8.2) mime-types (2.4.3) + mimemagic (0.3.0) mini_portile (0.5.2) minitest (5.5.1) multi_json (1.11.0) @@ -390,6 +394,7 @@ DEPENDENCIES growl guard-rspec haml-rails (~> 0.5.3) + hipchat (~> 1.5.0) httparty (= 0.11.0) jquery-rails jquery-turbolinks diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb index 39cf306..64bc698 100644 --- a/app/controllers/services_controller.rb +++ b/app/controllers/services_controller.rb @@ -50,7 +50,8 @@ class ServicesController < ApplicationController def service_params params.require(:service).permit( :type, :active, :webhook, :notify_only_broken_builds, - :email_recipients, :email_only_broken_builds, :email_add_pusher + :email_recipients, :email_only_broken_builds, :email_add_pusher, + :hipchat_token, :hipchat_room, :hipchat_server ) end end diff --git a/app/models/project.rb b/app/models/project.rb index 31ce6ab..c48b079 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -37,6 +37,7 @@ class Project < ActiveRecord::Base # Project services has_many :services, dependent: :destroy + has_one :hip_chat_service, dependent: :destroy has_one :slack_service, dependent: :destroy has_one :mail_service, dependent: :destroy @@ -210,7 +211,7 @@ ls -la end def available_services_names - %w(slack mail) + %w(slack mail hip_chat) end def build_missing_services diff --git a/app/models/project_services/hip_chat_message.rb b/app/models/project_services/hip_chat_message.rb new file mode 100644 index 0000000..85695cc --- /dev/null +++ b/app/models/project_services/hip_chat_message.rb @@ -0,0 +1,62 @@ +class HipChatMessage + attr_reader :build + + def initialize(build) + @build = build + end + + def to_s + lines = Array.new + lines.push("<a href=\"#{RoutesHelper.project_url(build.project)}\">#{build.project.name}</a> - ") + if build.commit.matrix? + lines.push("<a href=\"#{RoutesHelper.project_ref_commit_url(build.project, build.commit.ref, build.commit.sha)}\">Commit ##{commit.id}</a></br>") + else + lines.push("<a href=\"#{RoutesHelper.project_build_url(build.project, build)}\">Build '#{build.job_name}' ##{build.id}</a></br>") + end + lines.push("#{build.commit.short_sha} #{build.commit.git_author_name} - #{build.commit.git_commit_message}</br>") + lines.push("#{humanized_status} in #{build.commit.duration} second(s).") + lines.join('') + end + + def color + case status + when :success + 'green' + when :failed, :canceled + 'red' + when :pending, :running + 'yellow' + else + 'random' + end + end + + def notify? + [:failed, :canceled].include?(status) + end + + private + + def status + build.status.to_sym + end + + def humanized_status + case status + when :pending + "Pending" + when :running + "Running" + when :failed + "Failed" + when :success + "Successful" + when :canceled + "Canceled" + else + "Unknown" + end + end + +end + diff --git a/app/models/project_services/hip_chat_service.rb b/app/models/project_services/hip_chat_service.rb new file mode 100644 index 0000000..0faaca5 --- /dev/null +++ b/app/models/project_services/hip_chat_service.rb @@ -0,0 +1,67 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# + +class HipChatService < Service + prop_accessor :hipchat_token, :hipchat_room, :hipchat_server + boolean_accessor :notify_only_broken_builds + validates :hipchat_token, presence: true, if: :activated? + validates :hipchat_room, presence: true, if: :activated? + default_value_for :notify_only_broken_builds, true + + def title + "HipChat" + end + + def description + "Private group chat, video chat, instant messaging for teams" + end + + def help + end + + def to_param + 'hip_chat' + end + + def fields + [ + { type: 'text', name: 'hipchat_token', label: 'Token', placeholder: '' }, + { type: 'text', name: 'hipchat_room', label: 'Room', placeholder: '' }, + { type: 'text', name: 'hipchat_server', label: 'Server', placeholder: 'https://hipchat.example.com', help: 'Leave blank for default' }, + { type: 'checkbox', name: 'notify_only_broken_builds', label: 'Notify only broken builds' } + ] + end + + def execute build + commit = build.commit + return unless commit + return unless commit.builds_without_retry.include? build + + msg = HipChatMessage.new(build) + HipChatNotifierWorker.perform_async(hipchat_room, hipchat_token, msg.to_s, { + message_format: 'html', + color: msg.color, + notify: notify_only_broken_builds? && msg.notify? + }) + end + + private + + def default_options + { + hipchat_server: 'https://api.hipchat.com' + } + end + +end diff --git a/app/workers/hip_chat_notifier_worker.rb b/app/workers/hip_chat_notifier_worker.rb new file mode 100644 index 0000000..5bc7dda --- /dev/null +++ b/app/workers/hip_chat_notifier_worker.rb @@ -0,0 +1,9 @@ + +class HipChatNotifierWorker + include Sidekiq::Worker + + def perform(room, token, message, options={}) + client = HipChat::Client.new(token, api_version: 'v2') # v1.5.0 requires explicit version ( + client[room].send("GitLab CI", message, options) + end +end diff --git a/spec/models/project_services/hip_chat_service_spec.rb b/spec/models/project_services/hip_chat_service_spec.rb new file mode 100644 index 0000000..e578461 --- /dev/null +++ b/spec/models/project_services/hip_chat_service_spec.rb @@ -0,0 +1,48 @@ + +require 'spec_helper' + +describe HipChatService do + + describe "Validations" do + + context "active" do + before do + subject.active = true + end + + it { should validate_presence_of :hipchat_room } + it { should validate_presence_of :hipchat_token } + + end + end + + describe "Execute" do + + let(:service) { HipChatService.new } + let(:project) { FactoryGirl.create :project } + let(:commit) { FactoryGirl.create :commit, project: project } + let(:build) { FactoryGirl.create :build, commit: commit, status: 'failed' } + let(:api_url) { 'https://api.hipchat.com/v2/room/123/notification?auth_token=a1b2c3d4e5f6' } + + before do + service.stub( + project: project, + project_id: project.id, + notify_only_broken_builds: false, + hipchat_room: 123, + hipchat_token: 'a1b2c3d4e5f6' + ) + + WebMock.stub_request(:post, api_url) + end + + + it "should call the HipChat API" do + service.execute(build) + HipChatNotifierWorker.drain + + WebMock.should have_requested(:post, api_url).once + end + end +end + diff --git a/spec/models/slack_message_spec.rb b/spec/models/project_services/slack_message_spec.rb index 1fa2e31..1fa2e31 100644 --- a/spec/models/slack_message_spec.rb +++ b/spec/models/project_services/slack_message_spec.rb diff --git a/spec/models/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index e1c1428..e1c1428 100644 --- a/spec/models/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb |