diff options
-rw-r--r-- | CHANGELOG | 2 | ||||
-rw-r--r-- | app/controllers/projects/services_controller.rb | 3 | ||||
-rw-r--r-- | app/models/project.rb | 3 | ||||
-rw-r--r-- | app/models/project_services/pushover_service.rb | 113 | ||||
-rw-r--r-- | app/views/projects/services/_form.html.haml | 5 | ||||
-rw-r--r-- | features/project/service.feature | 6 | ||||
-rw-r--r-- | features/steps/project/services.rb | 23 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 1 | ||||
-rw-r--r-- | spec/models/pushover_service_spec.rb | 69 |
9 files changed, 223 insertions, 2 deletions
diff --git a/CHANGELOG b/CHANGELOG index 86f544091c8..14d2572f742 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,8 @@ v 7.4.0 - Zen mode for wiki and milestones (Robert Schilling) - Move Emoji parsing to html-pipeline-gitlab (Robert Schilling) - Font Awesome 4.2 integration (Sullivan Senechal) + - Add Pushover service integration (Sullivan Senechal) + - Add select field type for services options (Sullivan Senechal) v 7.3.2 - Fix creating new file via web editor diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index b143dec3a93..4c558e137ea 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -40,7 +40,8 @@ class Projects::ServicesController < Projects::ApplicationController def service_params params.require(:service).permit( :title, :token, :type, :active, :api_key, :subdomain, - :room, :recipients, :project_url + :room, :recipients, :project_url, + :user_key, :device, :priority, :sound ) end end diff --git a/app/models/project.rb b/app/models/project.rb index d228da192e4..44d63d37bee 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -64,6 +64,7 @@ class Project < ActiveRecord::Base has_one :assembla_service, dependent: :destroy has_one :gemnasium_service, dependent: :destroy has_one :slack_service, dependent: :destroy + has_one :pushover_service, dependent: :destroy has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_from_project, through: :forked_project_link # Merge Requests for target project should be removed with it @@ -311,7 +312,7 @@ class Project < ActiveRecord::Base end def available_services_names - %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack) + %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover) end def gitlab_ci? diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb new file mode 100644 index 00000000000..f247fde7762 --- /dev/null +++ b/app/models/project_services/pushover_service.rb @@ -0,0 +1,113 @@ +# == 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 PushoverService < Service + include HTTParty + base_uri 'https://api.pushover.net/1' + + prop_accessor :api_key, :user_key, :device, :priority, :sound + validates :api_key, :user_key, :priority, presence: true, if: :activated? + + def title + 'Pushover' + end + + def description + 'Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.' + end + + def to_param + 'pushover' + end + + def fields + [ + { type: 'text', name: 'api_key', placeholder: 'Your application key' }, + { type: 'text', name: 'user_key', placeholder: 'Your user key' }, + { type: 'text', name: 'device', placeholder: 'Leave blank for all active devices' }, + { type: 'select', name: 'priority', choices: + [ + ['Lowest Priority', -2], + ['Low Priority', -1], + ['Normal Priority', 0], + ['High Priority', 1] + ], + default_choice: 0 + }, + { type: 'select', name: 'sound', choices: + [ + ['Device default sound', nil], + ['Pushover (default)', 'pushover'], + ['Bike', 'bike'], + ['Bugle', 'bugle'], + ['Cash Register', 'cashregister'], + ['Classical', 'classical'], + ['Cosmic', 'cosmic'], + ['Falling', 'falling'], + ['Gamelan', 'gamelan'], + ['Incoming', 'incoming'], + ['Intermission', 'intermission'], + ['Magic', 'magic'], + ['Mechanical', 'mechanical'], + ['Piano Bar', 'pianobar'], + ['Siren', 'siren'], + ['Space Alarm', 'spacealarm'], + ['Tug Boat', 'tugboat'], + ['Alien Alarm (long)', 'alien'], + ['Climb (long)', 'climb'], + ['Persistent (long)', 'persistent'], + ['Pushover Echo (long)', 'echo'], + ['Up Down (long)', 'updown'], + ['None (silent)', 'none'] + ] + }, + ] + end + + def execute(push_data) + ref = push_data[:ref].gsub('refs/heads/', '') + before = push_data[:before] + after = push_data[:after] + + if before =~ /000000/ + message = "#{push_data[:user_name]} pushed new branch \"#{ref}\"." + elsif after =~ /000000/ + message = "#{push_data[:user_name]} deleted branch \"#{ref}\"." + else + message = "#{push_data[:user_name]} push to branch \"#{ref}\"." + end + + if push_data[:total_commits_count] > 0 + message << "\nTotal commits count: #{push_data[:total_commits_count]}" + end + + pushover_data = { + token: api_key, + user: user_key, + device: device, + priority: priority, + title: "#{project.name_with_namespace}", + message: message, + url: push_data[:repository][:homepage], + url_title: "See project #{project.name_with_namespace}" + } + + # Sound parameter MUST NOT be sent to API if not selected + if sound + pushover_data.merge!(sound: sound) + end + + PushoverService.post('/messages.json', body: pushover_data) + end +end diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index a5db7969a68..16d59d1fe9d 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -28,8 +28,11 @@ - @service.fields.each do |field| - name = field[:name] + - value = @service.send(name) - type = field[:type] - placeholder = field[:placeholder] + - choices = field[:choices] + - default_choice = field[:default_choice] .form-group = f.label name, class: "control-label" @@ -40,6 +43,8 @@ = f.text_area name, rows: 5, class: "form-control", placeholder: placeholder - elsif type == 'checkbox' = f.check_box name + - elsif type == 'select' + = f.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" } .form-actions = f.submit 'Save', class: 'btn btn-save' diff --git a/features/project/service.feature b/features/project/service.feature index a5af065c9e7..af88eaefa8f 100644 --- a/features/project/service.feature +++ b/features/project/service.feature @@ -43,6 +43,12 @@ Feature: Project Services And I fill Slack settings Then I should see Slack service settings saved + Scenario: Activate Pushover service + When I visit project "Shop" services page + And I click Pushover service link + And I fill Pushover settings + Then I should see Pushover service settings saved + Scenario: Activate email on push service When I visit project "Shop" services page And I click email on push service link diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb index b56b413eac8..d816fcafbaa 100644 --- a/features/steps/project/services.rb +++ b/features/steps/project/services.rb @@ -13,6 +13,7 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps page.should have_content 'Hipchat' page.should have_content 'GitLab CI' page.should have_content 'Assembla' + page.should have_content 'Pushover' end step 'I click gitlab-ci service link' do @@ -118,4 +119,26 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps find_field('Room').value.should == '#gitlab' find_field('Token').value.should == 'verySecret' end + + step 'I click Pushover service link' do + click_link 'Pushover' + end + + step 'I fill Pushover settings' do + check 'Active' + fill_in 'Api key', with: 'verySecret' + fill_in 'User key', with: 'verySecret' + fill_in 'Device', with: 'myDevice' + select 'High Priority', from: 'Priority' + select 'Bike', from: 'Sound' + click_button 'Save' + end + + step 'I should see Pushover service settings saved' do + find_field('Api key').value.should == 'verySecret' + find_field('User key').value.should == 'verySecret' + find_field('Device').value.should == 'myDevice' + find_field('Priority').find('option[selected]').value.should == '1' + find_field('Sound').find('option[selected]').value.should == 'bike' + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 524cab2b925..48b58400a1e 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -47,6 +47,7 @@ describe Project do it { should have_many(:protected_branches).dependent(:destroy) } it { should have_one(:forked_project_link).dependent(:destroy) } it { should have_one(:slack_service).dependent(:destroy) } + it { should have_one(:pushover_service).dependent(:destroy) } end describe "Mass assignment" do diff --git a/spec/models/pushover_service_spec.rb b/spec/models/pushover_service_spec.rb new file mode 100644 index 00000000000..59db69d7572 --- /dev/null +++ b/spec/models/pushover_service_spec.rb @@ -0,0 +1,69 @@ +# == 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 +# + +require 'spec_helper' + +describe PushoverService do + describe 'Associations' do + it { should belong_to :project } + it { should have_one :service_hook } + end + + describe 'Validations' do + context 'active' do + before do + subject.active = true + end + + it { should validate_presence_of :api_key } + it { should validate_presence_of :user_key } + it { should validate_presence_of :priority } + end + end + + describe 'Execute' do + let(:pushover) { PushoverService.new } + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:sample_data) { GitPushService.new.sample_data(project, user) } + + let(:api_key) { 'verySecret' } + let(:user_key) { 'verySecret' } + let(:device) { 'myDevice' } + let(:priority) { 0 } + let(:sound) { 'bike' } + let(:api_url) { 'https://api.pushover.net/1/messages.json' } + + before do + pushover.stub( + project: project, + project_id: project.id, + service_hook: true, + api_key: api_key, + user_key: user_key, + device: device, + priority: priority, + sound: sound + ) + + WebMock.stub_request(:post, api_url) + end + + it 'should call Pushover API' do + pushover.execute(sample_data) + + WebMock.should have_requested(:post, api_url).once + end + end +end |