summaryrefslogtreecommitdiff
path: root/app/models/project_services
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/project_services')
-rw-r--r--app/models/project_services/buildkite_service.rb2
-rw-r--r--app/models/project_services/builds_email_service.rb102
-rw-r--r--app/models/project_services/chat_message/build_message.rb102
-rw-r--r--app/models/project_services/chat_message/issue_message.rb3
-rw-r--r--app/models/project_services/chat_notification_service.rb18
-rw-r--r--app/models/project_services/drone_ci_service.rb6
-rw-r--r--app/models/project_services/hipchat_service.rb49
-rw-r--r--app/models/project_services/irker_service.rb3
-rw-r--r--app/models/project_services/issue_tracker_service.rb11
-rw-r--r--app/models/project_services/kubernetes_service.rb25
-rw-r--r--app/models/project_services/mattermost_service.rb15
-rw-r--r--app/models/project_services/mock_ci_service.rb82
-rw-r--r--app/models/project_services/monitoring_service.rb16
-rw-r--r--app/models/project_services/pivotaltracker_service.rb2
-rw-r--r--app/models/project_services/prometheus_service.rb93
-rw-r--r--app/models/project_services/pushover_service.rb45
-rw-r--r--app/models/project_services/slack_service.rb15
17 files changed, 290 insertions, 299 deletions
diff --git a/app/models/project_services/buildkite_service.rb b/app/models/project_services/buildkite_service.rb
index 0956c4a4ede..5fb95050b83 100644
--- a/app/models/project_services/buildkite_service.rb
+++ b/app/models/project_services/buildkite_service.rb
@@ -3,7 +3,7 @@ require "addressable/uri"
class BuildkiteService < CiService
include ReactiveService
- ENDPOINT = "https://buildkite.com"
+ ENDPOINT = "https://buildkite.com".freeze
prop_accessor :project_url, :token
boolean_accessor :enable_ssl_verification
diff --git a/app/models/project_services/builds_email_service.rb b/app/models/project_services/builds_email_service.rb
index ebd21e37189..0c526b53d72 100644
--- a/app/models/project_services/builds_email_service.rb
+++ b/app/models/project_services/builds_email_service.rb
@@ -1,107 +1,11 @@
+# This class is to be removed with 9.1
+# We should also by then remove BuildsEmailService from database
class BuildsEmailService < Service
- prop_accessor :recipients
- boolean_accessor :add_pusher
- boolean_accessor :notify_only_broken_builds
- validates :recipients, presence: true, if: ->(s) { s.activated? && !s.add_pusher? }
-
- def initialize_properties
- if properties.nil?
- self.properties = {}
- self.notify_only_broken_builds = true
- end
- end
-
- def title
- 'Builds emails'
- end
-
- def description
- 'Email the builds status to a list of recipients.'
- end
-
def self.to_param
'builds_email'
end
def self.supported_events
- %w(build)
- end
-
- def execute(push_data)
- return unless supported_events.include?(push_data[:object_kind])
- return unless should_build_be_notified?(push_data)
-
- recipients = all_recipients(push_data)
-
- if recipients.any?
- BuildEmailWorker.perform_async(
- push_data[:build_id],
- recipients,
- push_data
- )
- end
- end
-
- def can_test?
- project.builds.any?
- end
-
- def disabled_title
- "Please setup a build on your repository."
- end
-
- def test_data(project = nil, user = nil)
- Gitlab::DataBuilder::Build.build(project.builds.last)
- end
-
- def fields
- [
- { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by comma' },
- { type: 'checkbox', name: 'add_pusher', label: 'Add pusher to recipients list' },
- { type: 'checkbox', name: 'notify_only_broken_builds' },
- ]
- end
-
- def test(data)
- begin
- # bypass build status verification when testing
- data[:build_status] = "failed"
- data[:build_allow_failure] = false
-
- result = execute(data)
- rescue StandardError => error
- return { success: false, result: error }
- end
-
- { success: true, result: result }
- end
-
- def should_build_be_notified?(data)
- case data[:build_status]
- when 'success'
- !notify_only_broken_builds?
- when 'failed'
- !allow_failure?(data)
- else
- false
- end
- end
-
- def allow_failure?(data)
- data[:build_allow_failure] == true
- end
-
- def all_recipients(data)
- all_recipients = []
-
- unless recipients.blank?
- all_recipients += recipients.split(',').compact.reject(&:blank?)
- end
-
- if add_pusher? && data[:user][:email]
- all_recipients << data[:user][:email]
- end
-
- all_recipients
+ %w[]
end
end
diff --git a/app/models/project_services/chat_message/build_message.rb b/app/models/project_services/chat_message/build_message.rb
deleted file mode 100644
index c776e0a20c4..00000000000
--- a/app/models/project_services/chat_message/build_message.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-module ChatMessage
- class BuildMessage < BaseMessage
- attr_reader :sha
- attr_reader :ref_type
- attr_reader :ref
- attr_reader :status
- attr_reader :project_name
- attr_reader :project_url
- attr_reader :user_name
- attr_reader :user_url
- attr_reader :duration
- attr_reader :stage
- attr_reader :build_id
- attr_reader :build_name
-
- def initialize(params)
- @sha = params[:sha]
- @ref_type = params[:tag] ? 'tag' : 'branch'
- @ref = params[:ref]
- @project_name = params[:project_name]
- @project_url = params[:project_url]
- @status = params[:commit][:status]
- @user_name = params[:commit][:author_name]
- @user_url = params[:commit][:author_url]
- @duration = params[:commit][:duration]
- @stage = params[:build_stage]
- @build_name = params[:build_name]
- @build_id = params[:build_id]
- end
-
- def pretext
- ''
- end
-
- def fallback
- format(message)
- end
-
- def attachments
- [{ text: format(message), color: attachment_color }]
- end
-
- private
-
- def message
- "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_link} #{humanized_status} on build #{build_link} of stage #{stage} in #{duration} #{'second'.pluralize(duration)}"
- end
-
- def build_url
- "#{project_url}/builds/#{build_id}"
- end
-
- def build_link
- link(build_name, build_url)
- end
-
- def user_link
- link(user_name, user_url)
- end
-
- def format(string)
- Slack::Notifier::LinkFormatter.format(string)
- end
-
- def humanized_status
- case status
- when 'success'
- 'passed'
- else
- status
- end
- end
-
- def attachment_color
- if status == 'success'
- 'good'
- else
- 'danger'
- end
- end
-
- def branch_url
- "#{project_url}/commits/#{ref}"
- end
-
- def branch_link
- link(ref, branch_url)
- end
-
- def project_link
- link(project_name, project_url)
- end
-
- def commit_url
- "#{project_url}/commit/#{sha}/builds"
- end
-
- def commit_link
- link(Commit.truncate_sha(sha), commit_url)
- end
- end
-end
diff --git a/app/models/project_services/chat_message/issue_message.rb b/app/models/project_services/chat_message/issue_message.rb
index b96aca47e65..791e5b0cec7 100644
--- a/app/models/project_services/chat_message/issue_message.rb
+++ b/app/models/project_services/chat_message/issue_message.rb
@@ -51,7 +51,8 @@ module ChatMessage
title: issue_title,
title_link: issue_url,
text: format(description),
- color: "#C95823" }]
+ color: "#C95823"
+ }]
end
def project_link
diff --git a/app/models/project_services/chat_notification_service.rb b/app/models/project_services/chat_notification_service.rb
index 8468934425f..200be99f36b 100644
--- a/app/models/project_services/chat_notification_service.rb
+++ b/app/models/project_services/chat_notification_service.rb
@@ -6,7 +6,7 @@ class ChatNotificationService < Service
default_value_for :category, 'chat'
prop_accessor :webhook, :username, :channel
- boolean_accessor :notify_only_broken_builds, :notify_only_broken_pipelines
+ boolean_accessor :notify_only_broken_pipelines
validates :webhook, presence: true, url: true, if: :activated?
@@ -16,7 +16,6 @@ class ChatNotificationService < Service
if properties.nil?
self.properties = {}
- self.notify_only_broken_builds = true
self.notify_only_broken_pipelines = true
end
end
@@ -27,7 +26,7 @@ class ChatNotificationService < Service
def self.supported_events
%w[push issue confidential_issue merge_request note tag_push
- build pipeline wiki_page]
+ pipeline wiki_page]
end
def execute(data)
@@ -89,8 +88,6 @@ class ChatNotificationService < Service
ChatMessage::MergeMessage.new(data) unless is_update?(data)
when "note"
ChatMessage::NoteMessage.new(data)
- when "build"
- ChatMessage::BuildMessage.new(data) if should_build_be_notified?(data)
when "pipeline"
ChatMessage::PipelineMessage.new(data) if should_pipeline_be_notified?(data)
when "wiki_page"
@@ -125,17 +122,6 @@ class ChatNotificationService < Service
data[:object_attributes][:action] == 'update'
end
- def should_build_be_notified?(data)
- case data[:commit][:status]
- when 'success'
- !notify_only_broken_builds?
- when 'failed'
- true
- else
- false
- end
- end
-
def should_pipeline_be_notified?(data)
case data[:object_attributes][:status]
when 'success'
diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb
index 1ad9efac196..2717c240f05 100644
--- a/app/models/project_services/drone_ci_service.rb
+++ b/app/models/project_services/drone_ci_service.rb
@@ -39,7 +39,7 @@ class DroneCiService < CiService
def commit_status_path(sha, ref)
url = [drone_url,
"gitlab/#{project.full_path}/commits/#{sha}",
- "?branch=#{URI::encode(ref.to_s)}&access_token=#{token}"]
+ "?branch=#{URI.encode(ref.to_s)}&access_token=#{token}"]
URI.join(*url).to_s
end
@@ -74,7 +74,7 @@ class DroneCiService < CiService
def build_page(sha, ref)
url = [drone_url,
"gitlab/#{project.full_path}/redirect/commits/#{sha}",
- "?branch=#{URI::encode(ref.to_s)}"]
+ "?branch=#{URI.encode(ref.to_s)}"]
URI.join(*url).to_s
end
@@ -114,7 +114,7 @@ class DroneCiService < CiService
end
def merge_request_valid?(data)
- ['opened', 'reopened'].include?(data[:object_attributes][:state]) &&
+ %w(opened reopened).include?(data[:object_attributes][:state]) &&
data[:object_attributes][:merge_status] == 'unchecked'
end
end
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 72da219df28..8b181221bb0 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -6,16 +6,16 @@ class HipchatService < Service
a b i strong em br img pre code
table th tr td caption colgroup col thead tbody tfoot
ul ol li dl dt dd
- ]
+ ].freeze
prop_accessor :token, :room, :server, :color, :api_version
- boolean_accessor :notify_only_broken_builds, :notify
+ boolean_accessor :notify_only_broken_pipelines, :notify
validates :token, presence: true, if: :activated?
def initialize_properties
if properties.nil?
self.properties = {}
- self.notify_only_broken_builds = true
+ self.notify_only_broken_pipelines = true
end
end
@@ -36,17 +36,17 @@ class HipchatService < Service
{ type: 'text', name: 'token', placeholder: 'Room token' },
{ type: 'text', name: 'room', placeholder: 'Room name or ID' },
{ type: 'checkbox', name: 'notify' },
- { type: 'select', name: 'color', choices: ['yellow', 'red', 'green', 'purple', 'gray', 'random'] },
+ { type: 'select', name: 'color', choices: %w(yellow red green purple gray random) },
{ type: 'text', name: 'api_version',
placeholder: 'Leave blank for default (v2)' },
{ type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://hipchat.example.com' },
- { type: 'checkbox', name: 'notify_only_broken_builds' },
+ { type: 'checkbox', name: 'notify_only_broken_pipelines' },
]
end
def self.supported_events
- %w(push issue confidential_issue merge_request note tag_push build)
+ %w(push issue confidential_issue merge_request note tag_push pipeline)
end
def execute(data)
@@ -90,8 +90,8 @@ class HipchatService < Service
create_merge_request_message(data) unless is_update?(data)
when "note"
create_note_message(data)
- when "build"
- create_build_message(data) if should_build_be_notified?(data)
+ when "pipeline"
+ create_pipeline_message(data) if should_pipeline_be_notified?(data)
end
end
@@ -240,28 +240,29 @@ class HipchatService < Service
message
end
- 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]
+ def create_pipeline_message(data)
+ pipeline_attributes = data[:object_attributes]
+ pipeline_id = pipeline_attributes[:id]
+ ref_type = pipeline_attributes[:tag] ? 'tag' : 'branch'
+ ref = pipeline_attributes[:ref]
+ user_name = (data[:user] && data[:user][:name]) || 'API'
+ status = pipeline_attributes[:status]
+ duration = pipeline_attributes[:duration]
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>"
+ pipeline_url = "<a href=\"#{project_url}/pipelines/#{pipeline_id}\">##{pipeline_id}</a>"
- "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
+ "#{project_link}: Pipeline #{pipeline_url} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
end
def message_color(data)
- build_status_color(data) || color || 'yellow'
+ pipeline_status_color(data) || color || 'yellow'
end
- def build_status_color(data)
- return unless data && data[:object_kind] == 'build'
+ def pipeline_status_color(data)
+ return unless data && data[:object_kind] == 'pipeline'
- case data[:commit][:status]
+ case data[:object_attributes][:status]
when 'success'
'green'
else
@@ -294,10 +295,10 @@ class HipchatService < Service
end
end
- def should_build_be_notified?(data)
- case data[:commit][:status]
+ def should_pipeline_be_notified?(data)
+ case data[:object_attributes][:status]
when 'success'
- !notify_only_broken_builds?
+ !notify_only_broken_pipelines?
when 'failed'
true
else
diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb
index 5d6862d9faa..c62bb4fa120 100644
--- a/app/models/project_services/irker_service.rb
+++ b/app/models/project_services/irker_service.rb
@@ -33,7 +33,8 @@ class IrkerService < Service
end
def settings
- { server_host: server_host.present? ? server_host : 'localhost',
+ {
+ server_host: server_host.present? ? server_host : 'localhost',
server_port: server_port.present? ? server_port : 6659
}
end
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index 9e65fdbf9d6..50435b67eda 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -1,4 +1,6 @@
class IssueTrackerService < Service
+ validate :one_issue_tracker, if: :activated?, on: :manual_change
+
default_value_for :category, 'issue_tracker'
# Pattern used to extract links from comments
@@ -92,4 +94,13 @@ class IssueTrackerService < Service
def issues_tracker
Gitlab.config.issues_tracker[to_param]
end
+
+ def one_issue_tracker
+ return if template?
+ return if project.blank?
+
+ if project.services.external_issue_trackers.where.not(id: id).any?
+ errors.add(:base, 'Another issue tracker is already in use. Only one issue tracker service can be active at a time')
+ end
+ end
end
diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb
index f2f019c43bb..02fbd5497fa 100644
--- a/app/models/project_services/kubernetes_service.rb
+++ b/app/models/project_services/kubernetes_service.rb
@@ -3,7 +3,7 @@ class KubernetesService < DeploymentService
include Gitlab::Kubernetes
include ReactiveCaching
- self.reactive_cache_key = ->(service) { [ service.class.model_name.singular, service.project_id ] }
+ self.reactive_cache_key = ->(service) { [service.class.model_name.singular, service.project_id] }
# Namespace defaults to the project path, but can be overridden in case that
# is an invalid or inappropriate name
@@ -36,7 +36,7 @@ class KubernetesService < DeploymentService
def initialize_properties
if properties.nil?
self.properties = {}
- self.namespace = project.path if project.present?
+ self.namespace = "#{project.path}-#{project.id}" if project.present?
end
end
@@ -62,23 +62,19 @@ class KubernetesService < DeploymentService
{ type: 'text',
name: 'namespace',
title: 'Kubernetes namespace',
- placeholder: 'Kubernetes namespace',
- },
+ placeholder: 'Kubernetes namespace' },
{ type: 'text',
name: 'api_url',
title: 'API URL',
- placeholder: 'Kubernetes API URL, like https://kube.example.com/',
- },
+ placeholder: 'Kubernetes API URL, like https://kube.example.com/' },
{ type: 'text',
name: 'token',
title: 'Service token',
- placeholder: 'Service token',
- },
+ placeholder: 'Service token' },
{ type: 'textarea',
name: 'ca_pem',
title: 'Custom CA bundle',
- placeholder: 'Certificate Authority bundle (PEM format)',
- },
+ placeholder: 'Certificate Authority bundle (PEM format)' },
]
end
@@ -98,7 +94,12 @@ class KubernetesService < DeploymentService
{ key: 'KUBE_TOKEN', value: token, public: false },
{ key: 'KUBE_NAMESPACE', value: namespace, public: true }
]
- variables << { key: 'KUBE_CA_PEM', value: ca_pem, public: true } if ca_pem.present?
+
+ if ca_pem.present?
+ variables << { key: 'KUBE_CA_PEM', value: ca_pem, public: true }
+ variables << { key: 'KUBE_CA_PEM_FILE', value: ca_pem, public: true, file: true }
+ end
+
variables
end
@@ -167,7 +168,7 @@ class KubernetesService < DeploymentService
url = URI.parse(api_url)
prefix = url.path.sub(%r{/+\z}, '')
- url.path = [ prefix, *parts ].join("/")
+ url.path = [prefix, *parts].join("/")
url.to_s
end
diff --git a/app/models/project_services/mattermost_service.rb b/app/models/project_services/mattermost_service.rb
index 4ebc5318da1..1156d050622 100644
--- a/app/models/project_services/mattermost_service.rb
+++ b/app/models/project_services/mattermost_service.rb
@@ -15,10 +15,10 @@ class MattermostService < ChatNotificationService
'This service sends notifications about projects events to Mattermost channels.<br />
To set up this service:
<ol>
- <li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#enabling-incoming-webhooks">Enable incoming webhooks</a> in your Mattermost installation. </li>
- <li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#creating-integrations-using-incoming-webhooks">Add an incoming webhook</a> in your Mattermost team. The default channel can be overridden for each event. </li>
- <li>Paste the webhook <strong>URL</strong> into the field bellow. </li>
- <li>Select events below to enable notifications. The channel and username are optional. </li>
+ <li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#enabling-incoming-webhooks">Enable incoming webhooks</a> in your Mattermost installation.</li>
+ <li><a href="https://docs.mattermost.com/developer/webhooks-incoming.html#creating-integrations-using-incoming-webhooks">Add an incoming webhook</a> in your Mattermost team. The default channel can be overridden for each event.</li>
+ <li>Paste the webhook <strong>URL</strong> into the field below.</li>
+ <li>Select events below to enable notifications. The <strong>Channel handle</strong> and <strong>Username</strong> fields are optional.</li>
</ol>'
end
@@ -28,14 +28,13 @@ class MattermostService < ChatNotificationService
def default_fields
[
- { type: 'text', name: 'webhook', placeholder: 'http://mattermost_host/hooks/...' },
- { type: 'text', name: 'username', placeholder: 'username' },
- { type: 'checkbox', name: 'notify_only_broken_builds' },
+ { type: 'text', name: 'webhook', placeholder: 'e.g. http://mattermost_host/hooks/…' },
+ { type: 'text', name: 'username', placeholder: 'e.g. GitLab' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
]
end
def default_channel_placeholder
- "town-square"
+ "Channel handle (e.g. town-square)"
end
end
diff --git a/app/models/project_services/mock_ci_service.rb b/app/models/project_services/mock_ci_service.rb
new file mode 100644
index 00000000000..a8d581a1f67
--- /dev/null
+++ b/app/models/project_services/mock_ci_service.rb
@@ -0,0 +1,82 @@
+# For an example companion mocking service, see https://gitlab.com/gitlab-org/gitlab-mock-ci-service
+class MockCiService < CiService
+ ALLOWED_STATES = %w[failed canceled running pending success success_with_warnings skipped not_found].freeze
+
+ prop_accessor :mock_service_url
+ validates :mock_service_url, presence: true, url: true, if: :activated?
+
+ def title
+ 'MockCI'
+ end
+
+ def description
+ 'Mock an external CI'
+ end
+
+ def self.to_param
+ 'mock_ci'
+ end
+
+ def fields
+ [
+ { type: 'text',
+ name: 'mock_service_url',
+ placeholder: 'http://localhost:4004' },
+ ]
+ end
+
+ # Return complete url to build page
+ #
+ # Ex.
+ # http://jenkins.example.com:8888/job/test1/scm/bySHA1/12d65c
+ #
+ def build_page(sha, ref)
+ url = [mock_service_url,
+ "#{project.namespace.path}/#{project.path}/status/#{sha}"]
+
+ URI.join(*url).to_s
+ end
+
+ # Return string with build status or :error symbol
+ #
+ # Allowed states: 'success', 'failed', 'running', 'pending', 'skipped'
+ #
+ #
+ # Ex.
+ # @service.commit_status('13be4ac', 'master')
+ # # => 'success'
+ #
+ # @service.commit_status('2abe4ac', 'dev')
+ # # => 'running'
+ #
+ #
+ def commit_status(sha, ref)
+ response = HTTParty.get(commit_status_path(sha), verify: false)
+ read_commit_status(response)
+ rescue Errno::ECONNREFUSED
+ :error
+ end
+
+ def commit_status_path(sha)
+ url = [mock_service_url,
+ "#{project.namespace.path}/#{project.path}/status/#{sha}.json"]
+
+ URI.join(*url).to_s
+ end
+
+ def read_commit_status(response)
+ return :error unless response.code == 200 || response.code == 404
+
+ status = if response.code == 404
+ 'pending'
+ else
+ response['status']
+ end
+
+ if status.present? && ALLOWED_STATES.include?(status)
+ status
+ else
+ :error
+ end
+ end
+end
diff --git a/app/models/project_services/monitoring_service.rb b/app/models/project_services/monitoring_service.rb
new file mode 100644
index 00000000000..ea585721e8f
--- /dev/null
+++ b/app/models/project_services/monitoring_service.rb
@@ -0,0 +1,16 @@
+# Base class for monitoring services
+#
+# These services integrate with a deployment solution like Prometheus
+# to provide additional features for environments.
+class MonitoringService < Service
+ default_value_for :category, 'monitoring'
+
+ def self.supported_events
+ %w()
+ end
+
+ # Environments have a number of metrics
+ def metrics(environment)
+ raise NotImplementedError
+ end
+end
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index 9cc642591f4..d86f4f6f448 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -1,7 +1,7 @@
class PivotaltrackerService < Service
include HTTParty
- API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits'
+ API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits'.freeze
prop_accessor :token, :restrict_to_branch
validates :token, presence: true, if: :activated?
diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb
new file mode 100644
index 00000000000..375966b9efc
--- /dev/null
+++ b/app/models/project_services/prometheus_service.rb
@@ -0,0 +1,93 @@
+class PrometheusService < MonitoringService
+ include ReactiveCaching
+
+ self.reactive_cache_key = ->(service) { [service.class.model_name.singular, service.project_id] }
+ self.reactive_cache_lease_timeout = 30.seconds
+ self.reactive_cache_refresh_interval = 30.seconds
+ self.reactive_cache_lifetime = 1.minute
+
+ # Access to prometheus is directly through the API
+ prop_accessor :api_url
+
+ with_options presence: true, if: :activated? do
+ validates :api_url, url: true
+ end
+
+ after_save :clear_reactive_cache!
+
+ def initialize_properties
+ if properties.nil?
+ self.properties = {}
+ end
+ end
+
+ def title
+ 'Prometheus'
+ end
+
+ def description
+ 'Prometheus monitoring'
+ end
+
+ def help
+ 'Retrieves `container_cpu_usage_seconds_total` and `container_memory_usage_bytes` from the configured Prometheus server. An `environment` label is required on each metric to identify the Environment.'
+ end
+
+ def self.to_param
+ 'prometheus'
+ end
+
+ def fields
+ [
+ {
+ type: 'text',
+ name: 'api_url',
+ title: 'API URL',
+ placeholder: 'Prometheus API Base URL, like http://prometheus.example.com/'
+ }
+ ]
+ end
+
+ # Check we can connect to the Prometheus API
+ def test(*args)
+ client.ping
+
+ { success: true, result: 'Checked API endpoint' }
+ rescue Gitlab::PrometheusError => err
+ { success: false, result: err }
+ end
+
+ def metrics(environment)
+ with_reactive_cache(environment.slug) do |data|
+ data
+ end
+ end
+
+ # Cache metrics for specific environment
+ def calculate_reactive_cache(environment_slug)
+ return unless active? && project && !project.pending_delete?
+
+ memory_query = %{sum(container_memory_usage_bytes{container_name="app",environment="#{environment_slug}"})/1024/1024}
+ cpu_query = %{sum(rate(container_cpu_usage_seconds_total{container_name="app",environment="#{environment_slug}"}[2m]))}
+
+ {
+ success: true,
+ metrics: {
+ # Memory used in MB
+ memory_values: client.query_range(memory_query, start: 8.hours.ago),
+ memory_current: client.query(memory_query),
+ # CPU Usage rate in cores.
+ cpu_values: client.query_range(cpu_query, start: 8.hours.ago),
+ cpu_current: client.query(cpu_query)
+ },
+ last_update: Time.now.utc
+ }
+
+ rescue Gitlab::PrometheusError => err
+ { success: false, result: err.message }
+ end
+
+ def client
+ @prometheus ||= Gitlab::Prometheus.new(api_url: api_url)
+ end
+end
diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb
index a963d27a376..3e618a8dbf1 100644
--- a/app/models/project_services/pushover_service.rb
+++ b/app/models/project_services/pushover_service.rb
@@ -29,25 +29,24 @@ class PushoverService < Service
['Normal Priority', 0],
['High Priority', 1]
],
- default_choice: 0
- },
+ default_choice: 0 },
{ type: 'select', name: 'sound', choices:
[
['Device default sound', nil],
['Pushover (default)', 'pushover'],
- ['Bike', 'bike'],
- ['Bugle', 'bugle'],
+ %w(Bike bike),
+ %w(Bugle bugle),
['Cash Register', 'cashregister'],
- ['Classical', 'classical'],
- ['Cosmic', 'cosmic'],
- ['Falling', 'falling'],
- ['Gamelan', 'gamelan'],
- ['Incoming', 'incoming'],
- ['Intermission', 'intermission'],
- ['Magic', 'magic'],
- ['Mechanical', 'mechanical'],
+ %w(Classical classical),
+ %w(Cosmic cosmic),
+ %w(Falling falling),
+ %w(Gamelan gamelan),
+ %w(Incoming incoming),
+ %w(Intermission intermission),
+ %w(Magic magic),
+ %w(Mechanical mechanical),
['Piano Bar', 'pianobar'],
- ['Siren', 'siren'],
+ %w(Siren siren),
['Space Alarm', 'spacealarm'],
['Tug Boat', 'tugboat'],
['Alien Alarm (long)', 'alien'],
@@ -56,8 +55,7 @@ class PushoverService < Service
['Pushover Echo (long)', 'echo'],
['Up Down (long)', 'updown'],
['None (silent)', 'none']
- ]
- },
+ ] },
]
end
@@ -72,13 +70,14 @@ class PushoverService < Service
before = data[:before]
after = data[:after]
- if Gitlab::Git.blank_ref?(before)
- message = "#{data[:user_name]} pushed new branch \"#{ref}\"."
- elsif Gitlab::Git.blank_ref?(after)
- message = "#{data[:user_name]} deleted branch \"#{ref}\"."
- else
- message = "#{data[:user_name]} push to branch \"#{ref}\"."
- end
+ message =
+ if Gitlab::Git.blank_ref?(before)
+ "#{data[:user_name]} pushed new branch \"#{ref}\"."
+ elsif Gitlab::Git.blank_ref?(after)
+ "#{data[:user_name]} deleted branch \"#{ref}\"."
+ else
+ "#{data[:user_name]} push to branch \"#{ref}\"."
+ end
if data[:total_commits_count] > 0
message << "\nTotal commits count: #{data[:total_commits_count]}"
@@ -97,7 +96,7 @@ class PushoverService < Service
# Sound parameter MUST NOT be sent to API if not selected
if sound
- pushover_data.merge!(sound: sound)
+ pushover_data[:sound] = sound
end
PushoverService.post('/messages.json', body: pushover_data)
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index f77d2d7c60b..b657db6f9ee 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -13,11 +13,11 @@ class SlackService < ChatNotificationService
def help
'This service sends notifications about projects events to Slack channels.<br />
- To setup this service:
+ To set up this service:
<ol>
- <li><a href="https://slack.com/apps/A0F7XDUAZ-incoming-webhooks">Add an incoming webhook</a> in your Slack team. The default channel can be overridden for each event. </li>
- <li>Paste the <strong>Webhook URL</strong> into the field below. </li>
- <li>Select events below to enable notifications. The channel and username are optional. </li>
+ <li><a href="https://slack.com/apps/A0F7XDUAZ-incoming-webhooks">Add an incoming webhook</a> in your Slack team. The default channel can be overridden for each event.</li>
+ <li>Paste the <strong>Webhook URL</strong> into the field below.</li>
+ <li>Select events below to enable notifications. The <strong>Channel name</strong> and <strong>Username</strong> fields are optional.</li>
</ol>'
end
@@ -27,14 +27,13 @@ class SlackService < ChatNotificationService
def default_fields
[
- { type: 'text', name: 'webhook', placeholder: 'https://hooks.slack.com/services/...' },
- { type: 'text', name: 'username', placeholder: 'username' },
- { type: 'checkbox', name: 'notify_only_broken_builds' },
+ { type: 'text', name: 'webhook', placeholder: 'e.g. https://hooks.slack.com/services/…' },
+ { type: 'text', name: 'username', placeholder: 'e.g. GitLab' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
]
end
def default_channel_placeholder
- "#general"
+ "Channel name (e.g. general)"
end
end