summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG2
-rw-r--r--app/controllers/projects/services_controller.rb3
-rw-r--r--app/models/project.rb3
-rw-r--r--app/models/project_services/pushover_service.rb113
-rw-r--r--app/views/projects/services/_form.html.haml5
-rw-r--r--features/project/service.feature6
-rw-r--r--features/steps/project/services.rb23
-rw-r--r--spec/models/project_spec.rb1
-rw-r--r--spec/models/pushover_service_spec.rb69
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