summaryrefslogtreecommitdiff
path: root/app/models/project_services/ci
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/project_services/ci')
-rw-r--r--app/models/project_services/ci/hip_chat_message.rb78
-rw-r--r--app/models/project_services/ci/hip_chat_service.rb93
-rw-r--r--app/models/project_services/ci/mail_service.rb84
-rw-r--r--app/models/project_services/ci/slack_message.rb97
-rw-r--r--app/models/project_services/ci/slack_service.rb81
5 files changed, 433 insertions, 0 deletions
diff --git a/app/models/project_services/ci/hip_chat_message.rb b/app/models/project_services/ci/hip_chat_message.rb
new file mode 100644
index 00000000000..3e9f99e7eaf
--- /dev/null
+++ b/app/models/project_services/ci/hip_chat_message.rb
@@ -0,0 +1,78 @@
+module Ci
+ class HipChatMessage
+ attr_reader :build
+
+ def initialize(build)
+ @build = build
+ end
+
+ def to_s
+ lines = Array.new
+ lines.push("<a href=\"#{Ci::RoutesHelper.ci_project_url(project)}\">#{project.name}</a> - ")
+
+ if commit.matrix?
+ lines.push("<a href=\"#{Ci::RoutesHelper.ci_project_ref_commit_url(project, commit.ref, commit.sha)}\">Commit ##{commit.id}</a></br>")
+ else
+ first_build = commit.builds_without_retry.first
+ lines.push("<a href=\"#{Ci::RoutesHelper.ci_project_build_url(project, first_build)}\">Build '#{first_build.name}' ##{first_build.id}</a></br>")
+ end
+
+ lines.push("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}</br>")
+ lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).")
+ lines.join('')
+ end
+
+ def status_color(build_or_commit=nil)
+ build_or_commit ||= commit_status
+ case build_or_commit
+ when :success
+ 'green'
+ when :failed, :canceled
+ 'red'
+ else # :pending, :running or unknown
+ 'yellow'
+ end
+ end
+
+ def notify?
+ [:failed, :canceled].include?(commit_status)
+ end
+
+
+ private
+
+ def commit
+ build.commit
+ end
+
+ def project
+ commit.project
+ end
+
+ def build_status
+ build.status.to_sym
+ end
+
+ def commit_status
+ commit.status.to_sym
+ end
+
+ def humanized_status(build_or_commit=nil)
+ build_or_commit ||= commit_status
+ case build_or_commit
+ when :pending
+ "Pending"
+ when :running
+ "Running"
+ when :failed
+ "Failed"
+ when :success
+ "Successful"
+ when :canceled
+ "Canceled"
+ else
+ "Unknown"
+ end
+ end
+ end
+end
diff --git a/app/models/project_services/ci/hip_chat_service.rb b/app/models/project_services/ci/hip_chat_service.rb
new file mode 100644
index 00000000000..68acf71251e
--- /dev/null
+++ b/app/models/project_services/ci/hip_chat_service.rb
@@ -0,0 +1,93 @@
+# == 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
+#
+
+module Ci
+ 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 can_execute?(build)
+ return if build.allow_failure?
+
+ commit = build.commit
+ return unless commit
+ return unless commit.builds_without_retry.include? build
+
+ case commit.status.to_sym
+ when :failed
+ true
+ when :success
+ true unless notify_only_broken_builds?
+ else
+ false
+ end
+ end
+
+ def execute(build)
+ msg = Ci::HipChatMessage.new(build)
+ opts = default_options.merge(
+ token: hipchat_token,
+ room: hipchat_room,
+ server: server_url,
+ color: msg.status_color,
+ notify: msg.notify?
+ )
+ Ci::HipChatNotifierWorker.perform_async(msg.to_s, opts)
+ end
+
+ private
+
+ def default_options
+ {
+ service_name: 'GitLab CI',
+ message_format: 'html'
+ }
+ end
+
+ def server_url
+ if hipchat_server.blank?
+ 'https://api.hipchat.com'
+ else
+ hipchat_server
+ end
+ end
+ end
+end
diff --git a/app/models/project_services/ci/mail_service.rb b/app/models/project_services/ci/mail_service.rb
new file mode 100644
index 00000000000..3619a50fa96
--- /dev/null
+++ b/app/models/project_services/ci/mail_service.rb
@@ -0,0 +1,84 @@
+# == 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
+#
+
+module Ci
+ class MailService < Service
+ delegate :email_recipients, :email_recipients=,
+ :email_add_pusher, :email_add_pusher=,
+ :email_only_broken_builds, :email_only_broken_builds=, to: :project, prefix: false
+
+ before_save :update_project
+
+ default_value_for :active, true
+
+ def title
+ 'Mail'
+ end
+
+ def description
+ 'Email notification'
+ end
+
+ def to_param
+ 'mail'
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'email_recipients', label: 'Recipients', help: 'Whitespace-separated list of recipient addresses' },
+ { type: 'checkbox', name: 'email_add_pusher', label: 'Add pusher to recipients list' },
+ { type: 'checkbox', name: 'email_only_broken_builds', label: 'Notify only broken builds' }
+ ]
+ end
+
+ def can_execute?(build)
+ return if build.allow_failure?
+
+ # it doesn't make sense to send emails for retried builds
+ commit = build.commit
+ return unless commit
+ return unless commit.builds_without_retry.include?(build)
+
+ case build.status.to_sym
+ when :failed
+ true
+ when :success
+ true unless email_only_broken_builds
+ else
+ false
+ end
+ end
+
+ def execute(build)
+ build.commit.project_recipients.each do |recipient|
+ case build.status.to_sym
+ when :success
+ mailer.build_success_email(build.id, recipient)
+ when :failed
+ mailer.build_fail_email(build.id, recipient)
+ end
+ end
+ end
+
+ private
+
+ def update_project
+ project.save!
+ end
+
+ def mailer
+ Ci::Notify.delay
+ end
+ end
+end
diff --git a/app/models/project_services/ci/slack_message.rb b/app/models/project_services/ci/slack_message.rb
new file mode 100644
index 00000000000..7d884849bf3
--- /dev/null
+++ b/app/models/project_services/ci/slack_message.rb
@@ -0,0 +1,97 @@
+require 'slack-notifier'
+
+module Ci
+ class SlackMessage
+ def initialize(commit)
+ @commit = commit
+ end
+
+ def pretext
+ ''
+ end
+
+ def color
+ attachment_color
+ end
+
+ def fallback
+ format(attachment_message)
+ end
+
+ def attachments
+ fields = []
+
+ if commit.matrix?
+ commit.builds_without_retry.each do |build|
+ next if build.allow_failure?
+ next unless build.failed?
+ fields << {
+ title: build.name,
+ value: "Build <#{Ci::RoutesHelper.ci_project_build_url(project, build)}|\##{build.id}> failed in #{build.duration.to_i} second(s)."
+ }
+ end
+ end
+
+ [{
+ text: attachment_message,
+ color: attachment_color,
+ fields: fields
+ }]
+ end
+
+ private
+
+ attr_reader :commit
+
+ def attachment_message
+ out = "<#{Ci::RoutesHelper.ci_project_url(project)}|#{project_name}>: "
+ if commit.matrix?
+ out << "Commit <#{Ci::RoutesHelper.ci_project_ref_commit_url(project, commit.ref, commit.sha)}|\##{commit.id}> "
+ else
+ build = commit.builds_without_retry.first
+ out << "Build <#{Ci::RoutesHelper.ci_project_build_url(project, build)}|\##{build.id}> "
+ end
+ out << "(<#{commit_sha_link}|#{commit.short_sha}>) "
+ out << "of <#{commit_ref_link}|#{commit.ref}> "
+ out << "by #{commit.git_author_name} " if commit.git_author_name
+ out << "#{commit_status} in "
+ out << "#{commit.duration} second(s)"
+ end
+
+ def format(string)
+ Slack::Notifier::LinkFormatter.format(string)
+ end
+
+ def project
+ commit.project
+ end
+
+ def project_name
+ project.name
+ end
+
+ def commit_sha_link
+ "#{project.gitlab_url}/commit/#{commit.sha}"
+ end
+
+ def commit_ref_link
+ "#{project.gitlab_url}/commits/#{commit.ref}"
+ end
+
+ def attachment_color
+ if commit.success?
+ 'good'
+ else
+ 'danger'
+ end
+ end
+
+ def commit_status
+ if commit.success?
+ 'succeeded'
+ else
+ 'failed'
+ end
+ end
+ end
+end
diff --git a/app/models/project_services/ci/slack_service.rb b/app/models/project_services/ci/slack_service.rb
new file mode 100644
index 00000000000..c9a7f865a25
--- /dev/null
+++ b/app/models/project_services/ci/slack_service.rb
@@ -0,0 +1,81 @@
+# == 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
+#
+
+module Ci
+ class SlackService < Service
+ prop_accessor :webhook
+ boolean_accessor :notify_only_broken_builds
+ validates :webhook, presence: true, if: :activated?
+
+ default_value_for :notify_only_broken_builds, true
+
+ def title
+ 'Slack'
+ end
+
+ def description
+ 'A team communication tool for the 21st century'
+ end
+
+ def to_param
+ 'slack'
+ end
+
+ def help
+ 'Visit https://www.slack.com/services/new/incoming-webhook. Then copy link and save project!' unless webhook.present?
+ end
+
+ def fields
+ [
+ { type: 'text', name: 'webhook', label: 'Webhook URL', placeholder: '' },
+ { type: 'checkbox', name: 'notify_only_broken_builds', label: 'Notify only broken builds' }
+ ]
+ end
+
+ def can_execute?(build)
+ return if build.allow_failure?
+
+ commit = build.commit
+ return unless commit
+ return unless commit.builds_without_retry.include?(build)
+
+ case commit.status.to_sym
+ when :failed
+ true
+ when :success
+ true unless notify_only_broken_builds?
+ else
+ false
+ end
+ end
+
+ def execute(build)
+ message = Ci::SlackMessage.new(build.commit)
+ options = default_options.merge(
+ color: message.color,
+ fallback: message.fallback,
+ attachments: message.attachments
+ )
+ Ci::SlackNotifierWorker.perform_async(webhook, message.pretext, options)
+ end
+
+ private
+
+ def default_options
+ {
+ username: 'GitLab CI'
+ }
+ end
+ end
+end