summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock2
-rw-r--r--Gemfile.rails5.lock2
-rw-r--r--app/models/project.rb1
-rw-r--r--app/models/project_services/hangouts_chat_service.rb67
-rw-r--r--app/models/service.rb1
-rw-r--r--changelogs/unreleased/hangouts_chat_integration.yml5
-rw-r--r--doc/api/services.md48
-rw-r--r--doc/user/project/integrations/hangouts_chat.md27
-rw-r--r--doc/user/project/integrations/img/hangouts_chat_configuration.pngbin0 -> 101788 bytes
-rw-r--r--doc/user/project/integrations/project_services.md1
-rw-r--r--lib/api/services.rb9
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/models/project_services/hangouts_chat_service_spec.rb246
-rw-r--r--spec/models/project_spec.rb1
15 files changed, 414 insertions, 0 deletions
diff --git a/Gemfile b/Gemfile
index 0ad5df90c3c..41190e71409 100644
--- a/Gemfile
+++ b/Gemfile
@@ -220,6 +220,9 @@ gem 'gemnasium-gitlab-service', '~> 0.2'
# Slack integration
gem 'slack-notifier', '~> 1.5.1'
+# Hangouts Chat integration
+gem 'hangouts-chat', '~> 0.0.5'
+
# Asana integration
gem 'asana', '~> 0.6.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 1d9c75f154c..0976169bb11 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -387,6 +387,7 @@ GEM
temple (>= 0.8.0)
thor
tilt
+ hangouts-chat (0.0.5)
hashdiff (0.3.4)
hashie (3.5.7)
hashie-forbidden_attributes (0.1.1)
@@ -1062,6 +1063,7 @@ DEPENDENCIES
grpc (~> 1.11.0)
haml_lint (~> 0.26.0)
hamlit (~> 2.8.8)
+ hangouts-chat (~> 0.0.5)
hashie-forbidden_attributes
health_check (~> 2.6.0)
hipchat (~> 1.5.0)
diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock
index 2d12faa28d9..1cf612fd4a6 100644
--- a/Gemfile.rails5.lock
+++ b/Gemfile.rails5.lock
@@ -390,6 +390,7 @@ GEM
temple (>= 0.8.0)
thor
tilt
+ hangouts-chat (0.0.5)
hashdiff (0.3.4)
hashie (3.5.7)
hashie-forbidden_attributes (0.1.1)
@@ -1072,6 +1073,7 @@ DEPENDENCIES
grpc (~> 1.11.0)
haml_lint (~> 0.26.0)
hamlit (~> 2.8.8)
+ hangouts-chat (~> 0.0.5)
hashie-forbidden_attributes
health_check (~> 2.6.0)
hipchat (~> 1.5.0)
diff --git a/app/models/project.rb b/app/models/project.rb
index ae0a13b17dc..7d37c3b3893 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -154,6 +154,7 @@ class Project < ActiveRecord::Base
has_one :mock_monitoring_service
has_one :microsoft_teams_service
has_one :packagist_service
+ has_one :hangouts_chat_service
# TODO: replace these relations with the fork network versions
has_one :forked_project_link, foreign_key: "forked_to_project_id"
diff --git a/app/models/project_services/hangouts_chat_service.rb b/app/models/project_services/hangouts_chat_service.rb
new file mode 100644
index 00000000000..a8512c5f57c
--- /dev/null
+++ b/app/models/project_services/hangouts_chat_service.rb
@@ -0,0 +1,67 @@
+require 'hangouts_chat'
+
+class HangoutsChatService < ChatNotificationService
+ def title
+ 'Hangouts Chat'
+ end
+
+ def description
+ 'Receive event notifications in Google Hangouts Chat'
+ end
+
+ def self.to_param
+ 'hangouts_chat'
+ end
+
+ def help
+ 'This service sends notifications about projects events to Google Hangouts Chat room.<br />
+ To set up this service:
+ <ol>
+ <li><a href="https://developers.google.com/hangouts/chat/how-tos/webhooks">Set up an incoming webhook for your room</a>. All notifications will come to this room.</li>
+ <li>Paste the <strong>Webhook URL</strong> into the field below.</li>
+ <li>Select events below to enable notifications.</li>
+ </ol>'
+ end
+
+ def event_field(event)
+ end
+
+ def default_channel_placeholder
+ end
+
+ def webhook_placeholder
+ 'https://chat.googleapis.com/v1/spaces…'
+ end
+
+ def default_fields
+ [
+ { type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
+ { type: 'checkbox', name: 'notify_only_broken_pipelines' },
+ { type: 'checkbox', name: 'notify_only_default_branch' }
+ ]
+ end
+
+ private
+
+ def notify(message, opts)
+ simple_text = parse_simple_text_message(message)
+ HangoutsChat::Sender.new(webhook).simple(simple_text)
+ end
+
+ def parse_simple_text_message(message)
+ header = message.pretext
+ return header if message.attachments.empty?
+
+ attachment = message.attachments.first
+ title = format_attachment_title(attachment)
+ body = attachment[:text]
+
+ [header, title, body].compact.join("\n")
+ end
+
+ def format_attachment_title(attachment)
+ return attachment[:title] unless attachment[:title_link]
+
+ "<#{attachment[:title_link]}|#{attachment[:title]}>"
+ end
+end
diff --git a/app/models/service.rb b/app/models/service.rb
index ad835293b46..cbfe0c6eedd 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -254,6 +254,7 @@ class Service < ActiveRecord::Base
emails_on_push
external_wiki
flowdock
+ hangouts_chat
hipchat
irker
jira
diff --git a/changelogs/unreleased/hangouts_chat_integration.yml b/changelogs/unreleased/hangouts_chat_integration.yml
new file mode 100644
index 00000000000..bf3484a6d02
--- /dev/null
+++ b/changelogs/unreleased/hangouts_chat_integration.yml
@@ -0,0 +1,5 @@
+---
+title: Add Hangouts Chat integration
+merge_request: 20290
+author: Kukovskii Vladimir
+type: added
diff --git a/doc/api/services.md b/doc/api/services.md
index aeb48ccc36c..efa173180bb 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -443,6 +443,54 @@ Get Gemnasium service settings for a project.
GET /projects/:id/services/gemnasium
```
+## Hangouts Chat
+
+Google GSuite team collaboration tool.
+
+>**Note:** This service was [introduced in v11.2](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20290)
+
+### Create/Edit Hangouts Chat service
+
+Set Hangouts Chat service for a project.
+
+```
+PUT /projects/:id/services/hangouts_chat
+```
+
+>**Note:** Specific event parameters (e.g. `push_events` flag) were [introduced in v10.4][11435]
+
+Parameters:
+
+| Parameter | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `webhook` | string | true | The Hangouts Chat webhook. e.g. https://chat.googleapis.com/v1/spaces... |
+| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines |
+| `notify_only_default_branch` | boolean | false | Send notifications only for the default branch |
+| `push_events` | boolean | false | Enable notifications for push events |
+| `issues_events` | boolean | false | Enable notifications for issue events |
+| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events |
+| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
+| `tag_push_events` | boolean | false | Enable notifications for tag push events |
+| `note_events` | boolean | false | Enable notifications for note events |
+| `pipeline_events` | boolean | false | Enable notifications for pipeline events |
+| `wiki_page_events` | boolean | false | Enable notifications for wiki page events |
+
+### Delete Hangouts Chat service
+
+Delete Hangouts Chat service for a project.
+
+```
+DELETE /projects/:id/services/hangouts_chat
+```
+
+### Get Hangouts Chat service settings
+
+Get Hangouts Chat service settings for a project.
+
+```
+GET /projects/:id/services/hangouts_chat
+```
+
## HipChat
Private group chat and IM
diff --git a/doc/user/project/integrations/hangouts_chat.md b/doc/user/project/integrations/hangouts_chat.md
new file mode 100644
index 00000000000..6ab44420a10
--- /dev/null
+++ b/doc/user/project/integrations/hangouts_chat.md
@@ -0,0 +1,27 @@
+# Hangouts Chat service
+
+The Hangouts Chat service sends notifications from GitLab to the room for which the webhook was created.
+
+## On Hangouts Chat
+
+1. Open the chat room in which you want to see the notifications.
+1. From the chat room menu, select **Configure Webhooks**.
+1. Click on **ADD WEBHOOK** and fill in the name of the bot that will post the messages. Optionally define avatar.
+1. Click **SAVE** and copy the **Webhook URL** of your webhook.
+
+See also [the Hangouts Chat documentation for configuring incoming webhooks](https://developers.google.com/hangouts/chat/how-tos/webhooks)
+
+## On GitLab
+
+When you have the **Webhook URL** for your Hangouts Chat room webhook, you can setup the GitLab service.
+
+1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) in your project's settings, i.e. **Project > Settings > Integrations**.
+1. Select the **Hangouts Chat** project service to configure it.
+1. Check the **Active** checkbox to turn on the service.
+1. Check the checkboxes corresponding to the GitLab events you want to receive.
+1. Paste the **Webhook URL** that you copied from the Hangouts Chat configuration step.
+1. Configure the remaining options and click `Save changes`.
+
+Your Hangouts Chat room will now start receiving GitLab event notifications as configured.
+
+![Hangouts Chat configuration](img/hangouts_chat_configuration.png)
diff --git a/doc/user/project/integrations/img/hangouts_chat_configuration.png b/doc/user/project/integrations/img/hangouts_chat_configuration.png
new file mode 100644
index 00000000000..33fadbe6547
--- /dev/null
+++ b/doc/user/project/integrations/img/hangouts_chat_configuration.png
Binary files differ
diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md
index 8c51eb9915e..05ee1b4e6d7 100644
--- a/doc/user/project/integrations/project_services.md
+++ b/doc/user/project/integrations/project_services.md
@@ -35,6 +35,7 @@ Click on the service links to see further configuration instructions and details
| External Wiki | Replaces the link to the internal wiki with a link to an external wiki |
| Flowdock | Flowdock is a collaboration web app for technical teams |
| Gemnasium _(Has been deprecated in GitLab 11.0)_ | Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities |
+| [Hangouts Chat](hangouts_chat.md) | Receive events notifications in Google Hangouts Chat |
| [HipChat](hipchat.md) | Private group chat and IM |
| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway |
| [JIRA](jira.md) | JIRA issue tracker |
diff --git a/lib/api/services.rb b/lib/api/services.rb
index 553e8dff4b9..1f2bf546cd7 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -368,6 +368,14 @@ module API
desc: "The project's slug on gemnasium.com"
}
],
+ 'hangouts-chat' => [
+ {
+ required: true,
+ name: :webhook,
+ type: String,
+ desc: 'The Hangouts Chat webhook. e.g. https://chat.googleapis.com/v1/spaces…'
+ }
+ ],
'hipchat' => [
{
required: true,
@@ -688,6 +696,7 @@ module API
ExternalWikiService,
FlowdockService,
GemnasiumService,
+ HangoutsChatService,
HipchatService,
IrkerService,
JiraService,
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 084ce3066d6..db5aab0cd76 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -211,6 +211,7 @@ project:
- slack_service
- microsoft_teams_service
- mattermost_service
+- hangouts_chat_service
- buildkite_service
- bamboo_service
- teamcity_service
diff --git a/spec/models/project_services/hangouts_chat_service_spec.rb b/spec/models/project_services/hangouts_chat_service_spec.rb
new file mode 100644
index 00000000000..cfa55188a64
--- /dev/null
+++ b/spec/models/project_services/hangouts_chat_service_spec.rb
@@ -0,0 +1,246 @@
+require 'spec_helper'
+
+describe HangoutsChatService do
+ describe 'Associations' do
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
+ end
+
+ describe 'Validations' do
+ context 'when service is active' do
+ before do
+ subject.active = true
+ end
+
+ it { is_expected.to validate_presence_of(:webhook) }
+ it_behaves_like 'issue tracker service URL attribute', :webhook
+ end
+
+ context 'when service is inactive' do
+ before do
+ subject.active = false
+ end
+
+ it { is_expected.not_to validate_presence_of(:webhook) }
+ end
+ end
+
+ describe '#execute' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:webhook_url) { 'https://example.gitlab.com/' }
+
+ before do
+ allow(subject).to receive_messages(
+ project: project,
+ project_id: project.id,
+ service_hook: true,
+ webhook: webhook_url
+ )
+
+ WebMock.stub_request(:post, webhook_url)
+ end
+
+ shared_examples 'Hangouts Chat service' do
+ it 'calls Hangouts Chat API' do
+ subject.execute(sample_data)
+
+ expect(WebMock)
+ .to have_requested(:post, webhook_url)
+ .with { |req| req.body =~ /\A{"text":.+}\Z/ }
+ .once
+ end
+ end
+
+ context 'with push events' do
+ let(:sample_data) do
+ Gitlab::DataBuilder::Push.build_sample(project, user)
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+
+ it 'specifies the webhook when it is configured' do
+ expect(HangoutsChat::Sender).to receive(:new).with(webhook_url).and_return(double(:hangouts_chat_service).as_null_object)
+
+ subject.execute(sample_data)
+ end
+
+ context 'with not default branch' do
+ let(:sample_data) do
+ Gitlab::DataBuilder::Push.build(project, user, nil, nil, 'not-the-default-branch')
+ end
+
+ context 'when notify_only_default_branch enabled' do
+ before do
+ subject.notify_only_default_branch = true
+ end
+
+ it 'does not call the Hangouts Chat API' do
+ result = subject.execute(sample_data)
+
+ expect(result).to be_falsy
+ end
+ end
+
+ context 'when notify_only_default_branch disabled' do
+ before do
+ subject.notify_only_default_branch = false
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+ end
+ end
+
+ context 'with issue events' do
+ let(:opts) { { title: 'Awesome issue', description: 'please fix' } }
+ let(:sample_data) do
+ service = Issues::CreateService.new(project, user, opts)
+ issue = service.execute
+ service.hook_data(issue, 'open')
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+
+ context 'with merge events' do
+ let(:opts) do
+ {
+ title: 'Awesome merge_request',
+ description: 'please fix',
+ source_branch: 'feature',
+ target_branch: 'master'
+ }
+ end
+
+ let(:sample_data) do
+ service = MergeRequests::CreateService.new(project, user, opts)
+ merge_request = service.execute
+ service.hook_data(merge_request, 'open')
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+
+ context 'with wiki page events' do
+ let(:opts) do
+ {
+ title: 'Awesome wiki_page',
+ content: 'Some text describing some thing or another',
+ format: 'md',
+ message: 'user created page: Awesome wiki_page'
+ }
+ end
+ let(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: opts) }
+ let(:sample_data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') }
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+
+ context 'with note events' do
+ let(:sample_data) { Gitlab::DataBuilder::Note.build(note, user) }
+
+ context 'with commit comment' do
+ let(:note) do
+ create(:note_on_commit, author: user,
+ project: project,
+ commit_id: project.repository.commit.id,
+ note: 'a comment on a commit')
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+
+ context 'with merge request comment' do
+ let(:note) do
+ create(:note_on_merge_request, project: project,
+ note: 'merge request note')
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+
+ context 'with issue comment' do
+ let(:note) do
+ create(:note_on_issue, project: project, note: 'issue note')
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+
+ context 'with snippet comment' do
+ let(:note) do
+ create(:note_on_project_snippet, project: project,
+ note: 'snippet note')
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+ end
+
+ context 'with pipeline events' do
+ let(:pipeline) do
+ create(:ci_pipeline,
+ project: project, status: status,
+ sha: project.commit.sha, ref: project.default_branch)
+ end
+ let(:sample_data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
+
+ context 'with failed pipeline' do
+ let(:status) { 'failed' }
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+
+ context 'with succeeded pipeline' do
+ let(:status) { 'success' }
+
+ context 'with default notify_only_broken_pipelines' do
+ it 'does not call Hangouts Chat API' do
+ result = subject.execute(sample_data)
+
+ expect(result).to be_falsy
+ end
+ end
+
+ context 'when notify_only_broken_pipelines is false' do
+ before do
+ subject.notify_only_broken_pipelines = false
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+ end
+
+ context 'with not default branch' do
+ let(:pipeline) do
+ create(:ci_pipeline, project: project, status: 'failed', ref: 'not-the-default-branch')
+ end
+
+ context 'when notify_only_default_branch enabled' do
+ before do
+ subject.notify_only_default_branch = true
+ end
+
+ it 'does not call the Hangouts Chat API' do
+ result = subject.execute(sample_data)
+
+ expect(result).to be_falsy
+ end
+ end
+
+ context 'when notify_only_default_branch disabled' do
+ before do
+ subject.notify_only_default_branch = false
+ end
+
+ it_behaves_like 'Hangouts Chat service'
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index d200e5f2e42..b0ec725bf70 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -26,6 +26,7 @@ describe Project do
it { is_expected.to have_one(:slack_service) }
it { is_expected.to have_one(:microsoft_teams_service) }
it { is_expected.to have_one(:mattermost_service) }
+ it { is_expected.to have_one(:hangouts_chat_service) }
it { is_expected.to have_one(:packagist_service) }
it { is_expected.to have_one(:pushover_service) }
it { is_expected.to have_one(:asana_service) }