diff options
author | Drew Blessing <drew@gitlab.com> | 2016-01-14 08:20:23 -0600 |
---|---|---|
committer | Felipe Artur <felipefac@gmail.com> | 2016-10-26 15:02:16 -0200 |
commit | f4bc18d237413ac55e32ce16a23b3d2ab35a6976 (patch) | |
tree | 0b9cf78efee768bdcaa3a5175199b7475c1188b0 /app | |
parent | 2fc359a506b5997cb65b6d5f2f5c85df98fd1c69 (diff) | |
download | gitlab-ce-f4bc18d237413ac55e32ce16a23b3d2ab35a6976.tar.gz |
Refactor JIRA service to use gem
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/concerns/service_params.rb | 2 | ||||
-rw-r--r-- | app/models/project_services/jira_service.rb | 201 |
2 files changed, 97 insertions, 106 deletions
diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb index 4cb3be41064..c33d7eecb9f 100644 --- a/app/controllers/concerns/service_params.rb +++ b/app/controllers/concerns/service_params.rb @@ -18,7 +18,7 @@ module ServiceParams :add_pusher, :send_from_committer_email, :disable_diffs, :external_wiki_url, :notify, :color, :server_host, :server_port, :default_irc_uri, :enable_ssl_verification, - :jira_issue_transition_id] + :jira_issue_transition_id, :url, :project_key] # Parameters to ignore if no value is specified FILTER_BLANK_PARAMS = [:password] diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index f81b66fd219..580adcfba99 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -1,15 +1,35 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# template :boolean default(FALSE) +# push_events :boolean default(TRUE) +# issues_events :boolean default(TRUE) +# merge_requests_events :boolean default(TRUE) +# tag_push_events :boolean default(TRUE) +# note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null +# +require 'jira' + class JiraService < IssueTrackerService include HTTParty - include Gitlab::Routing.url_helpers + include Gitlab::Application.routes.url_helpers DEFAULT_API_VERSION = 2 - prop_accessor :username, :password, :api_url, :jira_issue_transition_id, - :title, :description, :project_url, :issues_url, :new_issue_url - - validates :api_url, presence: true, url: true, if: :activated? + prop_accessor :username, :password, :url, :project_key, + :jira_issue_transition_id, :title, :description - before_validation :set_api_url, :set_jira_issue_transition_id + before_validation :set_jira_issue_transition_id before_update :reset_password @@ -20,14 +40,34 @@ class JiraService < IssueTrackerService def reset_password # don't reset the password if a new one is provided - if api_url_changed? && !password_touched? + if url_changed? && !password_touched? self.password = nil end end + def options + url = URI.parse(self.url) + { + :username => self.username, + :password => self.password, + :site => URI.join(url, '/').to_s, + :context_path => url.path, + :auth_type => :basic, + :read_timeout => 120, + :use_ssl => url.scheme == 'https' + } + end + + def client + @client ||= ::JIRA::Client.new(options) + end + + def jira_project + @jira_project ||= client.Project.find(project_key) + end + def help - 'Setting `project_url`, `issues_url` and `new_issue_url` will '\ - 'allow a user to easily navigate to the Jira issue tracker. See the '\ + 'See the ' \ '[integration doc](http://doc.gitlab.com/ce/integration/external-issue-tracker.html) '\ 'for details.' end @@ -53,12 +93,25 @@ class JiraService < IssueTrackerService end def fields - super.push( - { type: 'text', name: 'api_url', placeholder: 'https://jira.example.com/rest/api/2' }, + [ + { type: 'text', name: 'url', title: 'URL', placeholder: 'https://jira.example.com' }, + { type: 'text', name: 'project_key', placeholder: 'PROJ' }, { type: 'text', name: 'username', placeholder: '' }, { type: 'password', name: 'password', placeholder: '' }, { type: 'text', name: 'jira_issue_transition_id', placeholder: '2' } - ) + ] + end + + def project_url + "#{url}/issues/?jql=project=#{project_key}" + end + + def issues_url + "#{url}/browse/:id" + end + + def new_issue_url + "#{url}/secure/CreateIssue.jspa" end def execute(push, issue = nil) @@ -72,7 +125,7 @@ class JiraService < IssueTrackerService end def create_cross_reference_note(mentioned, noteable, author) - issue_name = mentioned.id + issue_key = mentioned.id project = self.project noteable_name = noteable.class.name.underscore.downcase noteable_id = if noteable.is_a?(Commit) @@ -94,53 +147,25 @@ class JiraService < IssueTrackerService }, entity: { name: noteable_name.humanize.downcase, - url: entity_url, - title: noteable.title + url: entity_url } } - add_comment(data, issue_name) + add_comment(data, issue_key) end def test_settings - return unless api_url.present? - result = JiraService.get( - jira_api_test_url, - headers: { - 'Content-Type' => 'application/json', - 'Authorization' => "Basic #{auth}" - } - ) + return unless api_utrl.present? + # Test settings by getting the project + jira_project - case result.code - when 201, 200 - Rails.logger.info("#{self.class.name} SUCCESS #{result.code}: Successfully connected to #{api_url}.") - true - else - Rails.logger.info("#{self.class.name} ERROR #{result.code}: #{result.parsed_response}") - false - end - rescue Errno::ECONNREFUSED => e - Rails.logger.info "#{self.class.name} ERROR: #{e.message}. API URL: #{api_url}." + rescue Errno::ECONNREFUSED, JIRA::HTTPError => e + Rails.logger.info "#{self.class.name} Test ERROR: #{url} - #{e.message}" false end private - def build_api_url_from_project_url - server = URI(project_url) - default_ports = [["http", 80], ["https", 443]].include?([server.scheme, server.port]) - server_url = "#{server.scheme}://#{server.host}" - server_url.concat(":#{server.port}") unless default_ports - "#{server_url}/rest/api/#{DEFAULT_API_VERSION}" - rescue - "" # looks like project URL was not valid - end - - def set_api_url - self.api_url = build_api_url_from_project_url if self.api_url.blank? - end - def set_jira_issue_transition_id self.jira_issue_transition_id ||= "2" end @@ -149,7 +174,7 @@ class JiraService < IssueTrackerService commit_id = if entity.is_a?(Commit) entity.id elsif entity.is_a?(MergeRequest) - entity.diff_head_sha + entity.last_commit.id end commit_url = build_entity_url(:commit, commit_id) @@ -161,69 +186,47 @@ class JiraService < IssueTrackerService end def transition_issue(issue) - message = { - transition: { - id: jira_issue_transition_id - } - } - send_message(close_issue_url(issue.iid), message.to_json) + issue = client.Issue.find(issue.iid) + issue.transitions.build.save(transition: { id: jira_issue_transition_id }) end def add_issue_solved_comment(issue, commit_id, commit_url) - comment = { - body: "Issue solved with [#{commit_id}|#{commit_url}]." - } - - send_message(comment_url(issue.iid), comment.to_json) + comment = "Issue solved with [#{commit_id}|#{commit_url}]." + send_message(issue.iid, comment) end - def add_comment(data, issue_name) - url = comment_url(issue_name) + def add_comment(data, issue_key) user_name = data[:user][:name] user_url = data[:user][:url] entity_name = data[:entity][:name] entity_url = data[:entity][:url] - entity_title = data[:entity][:title] project_name = data[:project][:name] - message = { - body: %Q{[#{user_name}|#{user_url}] mentioned this issue in [a #{entity_name} of #{project_name}|#{entity_url}]:\n'#{entity_title}'} - } - - unless existing_comment?(issue_name, message[:body]) - send_message(url, message.to_json) - end - end + message = "[#{user_name}|#{user_url}] mentioned this issue in [a #{entity_name} of #{project_name}|#{entity_url}]." - def auth - require 'base64' - Base64.urlsafe_encode64("#{self.username}:#{self.password}") + # unless existing_comment?(issue_name, message[:body]) + send_message(issue_key, message) + # end end - def send_message(url, message) + def send_message(issue_key, message) return unless api_url.present? - result = JiraService.post( - url, - body: message, - headers: { - 'Content-Type' => 'application/json', - 'Authorization' => "Basic #{auth}" - } - ) - - message = case result.code - when 201, 200, 204 - "#{self.class.name} SUCCESS #{result.code}: Successfully posted to #{url}." - when 401 - "#{self.class.name} ERROR 401: Unauthorized. Check the #{self.username} credentials and JIRA access permissions and try again." - else - "#{self.class.name} ERROR #{result.code}: #{result.parsed_response}" - end + issue = client.Issue.find(issue_key) + issue.comments.build.save!(body: message) + + # message = case result.code + # when 201, 200, 204 + # "#{self.class.name} SUCCESS #{result.code}: Successfully posted to #{url}." + # when 401 + # "#{self.class.name} ERROR 401: Unauthorized. Check the #{self.username} credentials and JIRA access permissions and try again." + # else + # "#{self.class.name} ERROR #{result.code}: #{result.parsed_response}" + # end Rails.logger.info(message) message rescue URI::InvalidURIError, Errno::ECONNREFUSED => e - Rails.logger.info "#{self.class.name} ERROR: #{e.message}. Hostname: #{url}." + Rails.logger.info "#{self.class.name} Send message ERROR: #{url} - #{e.message}" end def existing_comment?(issue_name, new_comment) @@ -267,16 +270,4 @@ class JiraService < IssueTrackerService ) ) end - - def close_issue_url(issue_name) - "#{self.api_url}/issue/#{issue_name}/transitions" - end - - def comment_url(issue_name) - "#{self.api_url}/issue/#{issue_name}/comment" - end - - def jira_api_test_url - "#{self.api_url}/myself" - end end |