diff --git a/app/models/project.rb b/app/models/project.rb index 1da24ee649..336e2cea1a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -64,6 +64,7 @@ class Project < ActiveRecord::Base has_one :assembla_service, dependent: :destroy has_one :gemnasium_service, dependent: :destroy has_one :slack_service, dependent: :destroy + has_one :jira_service, dependent: :destroy has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_from_project, through: :forked_project_link # Merge Requests for target project should be removed with it @@ -316,13 +317,17 @@ class Project < ActiveRecord::Base end def available_services_names - %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack) + %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack jira) end def gitlab_ci? gitlab_ci_service && gitlab_ci_service.active end + def jira_tracker? + self.issues_tracker == "jira" + end + # For compatibility with old code def code path diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb new file mode 100644 index 0000000000..da10f20f00 --- /dev/null +++ b/app/models/project_services/jira_service.rb @@ -0,0 +1,95 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# token :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# project_url :string(255) +# subdomain :string(255) +# room :string(255) +# recipients :text +# api_key :string(255) +# username :string(255) +# password :string(255) + +class JiraService < Service + + include HTTParty + attr_accessible :project_url, :username, :password, :api_version + + validates :username, :password, presence: true, if: :activated? + before_validation :set_api_version + + def title + 'JIRA' + end + + def description + 'Bug, issue tracking, and project management system' + end + + def to_param + 'jira' + end + + def fields + [ + { type: 'text', name: 'project_url', placeholder: 'Url to JIRA, http://jira.example' }, + { type: 'text', name: 'username', placeholder: '' }, + { type: 'password', name: 'password', placeholder: '' }, + { type: 'text', name: 'api_version', placeholder: '2' } + ] + end + + def set_api_version + self.api_version = "2" + end + + def execute(push, issue = nil) + close_issue(push, issue) if issue + end + +private + + def close_issue(push_data, issue_name) + url = close_issue_url(issue_name) + commit_url = push_data[:commits].first[:url] + + message = { + 'update' => { + 'comment' => [{ + 'add' => { + 'body' => "Issue solved with #{commit_url}" + } + }] + }, + 'transition' => { + 'id' => '2' + } + } + + JiraService.post( + url, + body: message.to_json, + headers: { + 'Content-Type' => 'application/json', + 'Authorization' => "Basic #{auth}" + } + ) + end + + def close_issue_url(issue_name) + "#{self.project_url.chomp("/")}/rest/api/#{self.api_version}/issue/#{issue_name}/transitions" + end + + def auth + require 'base64' + Base64.urlsafe_encode64("#{self.username}:#{self.password}") + end +end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 715b569075..2f39ce571a 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -88,7 +88,11 @@ class GitPushService if !issues_to_close.empty? && is_default_branch issues_to_close.each do |issue| - Issues::CloseService.new(project, author, {}).execute(issue, commit) + if project.jira_tracker? && project.jira_service.active + project.jira_service.execute(push_data, issue) + else + Issues::CloseService.new(project, author, {}).execute(issue, commit) + end end end diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index 70b4537fd3..46f6dd5257 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -37,6 +37,8 @@ = f.text_area name, rows: 5, class: "form-control", placeholder: placeholder - elsif type == 'checkbox' = f.check_box name + - elsif type == 'password' + = f.password_field name, class: "form-control" .form-actions = f.submit 'Save', class: 'btn btn-save' diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index e4a67be428..b82bec2adf 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -74,7 +74,7 @@ production: &base # If a commit message matches this regular expression, all issues referenced from the matched text will be closed. # This happens when the commit is pushed or merged into the default branch of a project. # When not specified the default issue_closing_pattern as specified below will be used. - # issue_closing_pattern: '([Cc]lose[sd]|[Ff]ixe[sd]) #(\d+)' + # issue_closing_pattern: '([Cc]lose[sd]|[Ff]ixe[sd]) (#\d+|([A-Z\-]+-)\d+)' ## Default project features settings default_projects_features: diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 97f2954640..299dd8cab7 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -91,7 +91,7 @@ Settings.gitlab['signup_enabled'] ||= false Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? -Settings.gitlab['issue_closing_pattern'] = '([Cc]lose[sd]|[Ff]ixe[sd]) #(\d+)' if Settings.gitlab['issue_closing_pattern'].nil? +Settings.gitlab['issue_closing_pattern'] = '([Cc]lose[sd]|[Ff]ixe[sd]) (#\d+|([A-Z\-]+-)\d+)' if Settings.gitlab['issue_closing_pattern'].nil? Settings.gitlab['default_projects_features'] ||= {} Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil? Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.gitlab.default_projects_features['merge_requests'].nil? diff --git a/db/migrate/20140513095908_add_username_password_api_version_to_services.rb b/db/migrate/20140513095908_add_username_password_api_version_to_services.rb new file mode 100644 index 0000000000..407c930525 --- /dev/null +++ b/db/migrate/20140513095908_add_username_password_api_version_to_services.rb @@ -0,0 +1,7 @@ +class AddUsernamePasswordApiVersionToServices < ActiveRecord::Migration + def change + add_column :services, :username, :string + add_column :services, :password, :string + add_column :services, :api_version, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index a6f883914e..a8d0708cb0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140502125220) do +ActiveRecord::Schema.define(version: 20140513095908) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -280,6 +280,9 @@ ActiveRecord::Schema.define(version: 20140502125220) do t.string "room" t.text "recipients" t.string "api_key" + t.string "username" + t.string "password" + t.string "api_version" end add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index dca3d7a7be..5e2fadee42 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -181,7 +181,7 @@ module Gitlab link_to("##{identifier}", url, html_options.merge(title: "Issue: #{title}", class: "gfm gfm-issue #{html_options[:class]}")) end else - reference_jira_issue(identifier) if @project.issues_tracker == "jira" + reference_jira_issue(identifier) if @project.jira_tracker? end end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 94b01e808d..a95ff0b5a5 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -23,9 +23,13 @@ module Gitlab end def issues_for project - issues.map do |identifier| - project.issues.where(iid: identifier).first - end.reject(&:nil?) + if project.jira_tracker? + issues.uniq + else + issues.map do |identifier| + project.issues.where(iid: identifier).first + end.reject(&:nil?) + end end def merge_requests_for project