From 4e4ca27ab148f16d9252634e3e2f58447acdeeef Mon Sep 17 00:00:00 2001
From: Egor Lynko <flexoid@gmail.com>
Date: Wed, 10 Aug 2016 17:15:27 +0300
Subject: [PATCH] Ability to specify branches for pivotal tracker integration

---
 CHANGELOG                                     |  1 +
 .../pivotaltracker_service.rb                 | 31 ++++++--
 doc/api/services.md                           |  4 +-
 .../pivotaltracker_service_spec.rb            | 71 +++++++++++++++++++
 4 files changed, 101 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 6e096b480c0d..43fe73d9b9ab 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.
 
 v 8.11.0 (unreleased)
   - Remove the http_parser.rb dependency by removing the tinder gem. !5758 (tbalthazar)
+  - Ability to specify branches for Pivotal Tracker integration (Egor Lynko)
   - Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
   - Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres)
   - Fix the title of the toggle dropdown button. !5515 (herminiotorres)
diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb
index ad19b7795da8..5301f9fa0ff6 100644
--- a/app/models/project_services/pivotaltracker_service.rb
+++ b/app/models/project_services/pivotaltracker_service.rb
@@ -1,7 +1,9 @@
 class PivotaltrackerService < Service
   include HTTParty
 
-  prop_accessor :token
+  API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits'
+
+  prop_accessor :token, :restrict_to_branch
   validates :token, presence: true, if: :activated?
 
   def title
@@ -18,7 +20,17 @@ def to_param
 
   def fields
     [
-      { type: 'text', name: 'token', placeholder: '' }
+      {
+        type: 'text',
+        name: 'token',
+        placeholder: 'Pivotal Tracker API token.'
+      },
+      {
+        type: 'text',
+        name: 'restrict_to_branch',
+        placeholder: 'Comma-separated list of branches which will be ' \
+          'automatically inspected. Leave blank to include all branches.'
+      }
     ]
   end
 
@@ -28,8 +40,8 @@ def supported_events
 
   def execute(data)
     return unless supported_events.include?(data[:object_kind])
+    return unless allowed_branch?(data[:ref])
 
-    url = 'https://www.pivotaltracker.com/services/v5/source_commits'
     data[:commits].each do |commit|
       message = {
         'source_commit' => {
@@ -40,7 +52,7 @@ def execute(data)
         }
       }
       PivotaltrackerService.post(
-        url,
+        API_ENDPOINT,
         body: message.to_json,
         headers: {
           'Content-Type' => 'application/json',
@@ -49,4 +61,15 @@ def execute(data)
       )
     end
   end
+
+  private
+
+  def allowed_branch?(ref)
+    return true unless ref.present? && restrict_to_branch.present?
+
+    branch = Gitlab::Git.ref_name(ref)
+    allowed_branches = restrict_to_branch.split(',').map(&:strip)
+
+    branch.present? && allowed_branches.include?(branch)
+  end
 end
diff --git a/doc/api/services.md b/doc/api/services.md
index f821a6140471..579fdc0c8c97 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -355,7 +355,7 @@ PUT /projects/:id/services/gemnasium
 
 Parameters:
 
-- `api_key` (**required**) - Your personal API KEY on gemnasium.com 
+- `api_key` (**required**) - Your personal API KEY on gemnasium.com
 - `token` (**required**) - The project's slug on gemnasium.com
 
 ### Delete Gemnasium service
@@ -503,6 +503,7 @@ PUT /projects/:id/services/pivotaltracker
 Parameters:
 
 - `token` (**required**)
+- `restrict_to_branch` (optional) - Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.
 
 ### Delete PivotalTracker service
 
@@ -661,4 +662,3 @@ Get JetBrains TeamCity CI service settings for a project.
 ```
 GET /projects/:id/services/teamcity
 ```
-
diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb
index f37edd4d9709..d098d9885211 100644
--- a/spec/models/project_services/pivotaltracker_service_spec.rb
+++ b/spec/models/project_services/pivotaltracker_service_spec.rb
@@ -39,4 +39,75 @@
       it { is_expected.not_to validate_presence_of(:token) }
     end
   end
+
+  describe 'Execute' do
+    let(:service) do
+      PivotaltrackerService.new.tap do |service|
+        service.token = 'secret_api_token'
+      end
+    end
+
+    let(:url) { PivotaltrackerService::API_ENDPOINT }
+
+    def push_data(branch: 'master')
+      {
+        object_kind: 'push',
+        ref: "refs/heads/#{branch}",
+        commits: [
+          {
+            id: '21c12ea',
+            author: {
+              name: 'Some User'
+            },
+            url: 'https://example.com/commit',
+            message: 'commit message',
+          }
+        ]
+      }
+    end
+
+    before do
+      WebMock.stub_request(:post, url)
+    end
+
+    it 'should post correct message' do
+      service.execute(push_data)
+      expect(WebMock).to have_requested(:post, url).with(
+        body: {
+          'source_commit' => {
+            'commit_id' => '21c12ea',
+            'author' => 'Some User',
+            'url' => 'https://example.com/commit',
+            'message' => 'commit message'
+          }
+        },
+        headers: {
+          'Content-Type' => 'application/json',
+          'X-TrackerToken' => 'secret_api_token'
+        }
+      ).once
+    end
+
+    context 'when allowed branches is specified' do
+      let(:service) do
+        super().tap do |service|
+          service.restrict_to_branch = 'master,v10'
+        end
+      end
+
+      it 'should post message if branch is in the list' do
+        service.execute(push_data(branch: 'master'))
+        service.execute(push_data(branch: 'v10'))
+
+        expect(WebMock).to have_requested(:post, url).twice
+      end
+
+      it 'should not post message if branch is not in the list' do
+        service.execute(push_data(branch: 'mas'))
+        service.execute(push_data(branch: 'v11'))
+
+        expect(WebMock).not_to have_requested(:post, url)
+      end
+    end
+  end
 end
-- 
GitLab