Commit e1f77b9be071fac9f57e85b2f3853d2f333aeaab

Authored by Dmitriy Zaporozhets
2 parents d452ffc2 1dab19d0

Merge branch 'link-to-issue-tracker' of https://github.com/Undev/gitlabhq into U…

…ndev-link-to-issue-tracker

Conflicts:
	Gemfile.lock
@@ -46,6 +46,9 @@ gem "grape-entity", "~> 0.2.0" @@ -46,6 +46,9 @@ gem "grape-entity", "~> 0.2.0"
46 # based on human-friendly examples 46 # based on human-friendly examples
47 gem "stamp" 47 gem "stamp"
48 48
  49 +# Enumeration fields
  50 +gem 'enumerize'
  51 +
49 # Pagination 52 # Pagination
50 gem "kaminari", "~> 0.14.1" 53 gem "kaminari", "~> 0.14.1"
51 54
@@ -113,6 +116,7 @@ group :assets do @@ -113,6 +116,7 @@ group :assets do
113 gem 'bootstrap-sass', "2.2.1.1" 116 gem 'bootstrap-sass', "2.2.1.1"
114 gem "font-awesome-sass-rails", "~> 3.0.0" 117 gem "font-awesome-sass-rails", "~> 3.0.0"
115 gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' 118 gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
  119 + gem "gon"
116 end 120 end
117 121
118 group :development do 122 group :development do
@@ -146,6 +146,8 @@ GEM @@ -146,6 +146,8 @@ GEM
146 email_spec (1.4.0) 146 email_spec (1.4.0)
147 launchy (~> 2.1) 147 launchy (~> 2.1)
148 mail (~> 2.2) 148 mail (~> 2.2)
  149 + enumerize (0.5.1)
  150 + activesupport (>= 3.2)
149 erubis (2.7.0) 151 erubis (2.7.0)
150 escape_utils (0.2.4) 152 escape_utils (0.2.4)
151 eventmachine (1.0.0) 153 eventmachine (1.0.0)
@@ -184,10 +186,13 @@ GEM @@ -184,10 +186,13 @@ GEM
184 pyu-ruby-sasl (~> 0.0.3.1) 186 pyu-ruby-sasl (~> 0.0.3.1)
185 rubyntlm (~> 0.1.1) 187 rubyntlm (~> 0.1.1)
186 gitlab_yaml_db (1.0.0) 188 gitlab_yaml_db (1.0.0)
  189 + gon (4.0.2)
187 grape (0.3.1) 190 grape (0.3.1)
  191 + actionpack (>= 2.3.0)
188 activesupport 192 activesupport
189 grape-entity (~> 0.2.0) 193 grape-entity (~> 0.2.0)
190 hashie (~> 1.2) 194 hashie (~> 1.2)
  195 + json
191 multi_json (>= 1.3.2) 196 multi_json (>= 1.3.2)
192 multi_xml 197 multi_xml
193 rack 198 rack
@@ -473,6 +478,7 @@ DEPENDENCIES @@ -473,6 +478,7 @@ DEPENDENCIES
473 devise (~> 2.1.0) 478 devise (~> 2.1.0)
474 draper (~> 0.18.0) 479 draper (~> 0.18.0)
475 email_spec 480 email_spec
  481 + enumerize
476 factory_girl_rails 482 factory_girl_rails
477 ffaker 483 ffaker
478 font-awesome-sass-rails (~> 3.0.0) 484 font-awesome-sass-rails (~> 3.0.0)
@@ -484,6 +490,7 @@ DEPENDENCIES @@ -484,6 +490,7 @@ DEPENDENCIES
484 gitlab_meta (= 5.0) 490 gitlab_meta (= 5.0)
485 gitlab_omniauth-ldap (= 1.0.2) 491 gitlab_omniauth-ldap (= 1.0.2)
486 gitlab_yaml_db (= 1.0.0) 492 gitlab_yaml_db (= 1.0.0)
  493 + gon
487 grack! 494 grack!
488 grape (~> 0.3.1) 495 grape (~> 0.3.1)
489 grape-entity (~> 0.2.0) 496 grape-entity (~> 0.2.0)
app/assets/javascripts/projects.js.coffee
@@ -18,3 +18,18 @@ $ -> @@ -18,3 +18,18 @@ $ ->
18 # Ref switcher 18 # Ref switcher
19 $('.project-refs-select').on 'change', -> 19 $('.project-refs-select').on 'change', ->
20 $(@).parents('form').submit() 20 $(@).parents('form').submit()
  21 +
  22 + $('#project_issues_enabled').change ->
  23 + if ($(this).is(':checked') == true)
  24 + $('#project_issues_tracker').removeAttr('disabled')
  25 + else
  26 + $('#project_issues_tracker').attr('disabled', 'disabled')
  27 +
  28 + $('#project_issues_tracker').change()
  29 +
  30 + $('#project_issues_tracker').change ->
  31 + if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
  32 + $('#project_issues_tracker_id').attr('disabled', 'disabled')
  33 + else
  34 + $('#project_issues_tracker_id').removeAttr('disabled')
  35 +
app/controllers/application_controller.rb
@@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base @@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base
5 before_filter :add_abilities 5 before_filter :add_abilities
6 before_filter :dev_tools if Rails.env == 'development' 6 before_filter :dev_tools if Rails.env == 'development'
7 before_filter :default_headers 7 before_filter :default_headers
  8 + before_filter :add_gon_variables
8 9
9 protect_from_forgery 10 protect_from_forgery
10 11
@@ -148,4 +149,8 @@ class ApplicationController < ActionController::Base @@ -148,4 +149,8 @@ class ApplicationController < ActionController::Base
148 headers['X-Frame-Options'] = 'DENY' 149 headers['X-Frame-Options'] = 'DENY'
149 headers['X-XSS-Protection'] = '1; mode=block' 150 headers['X-XSS-Protection'] = '1; mode=block'
150 end 151 end
  152 +
  153 + def add_gon_variables
  154 + gon.default_issues_tracker = Project.issues_tracker.default_value
  155 + end
151 end 156 end
app/helpers/issues_helper.rb
@@ -40,4 +40,39 @@ module IssuesHelper @@ -40,4 +40,39 @@ module IssuesHelper
40 def issues_active_milestones 40 def issues_active_milestones
41 @project.milestones.active.order("id desc").all 41 @project.milestones.active.order("id desc").all
42 end 42 end
  43 +
  44 + def url_for_project_issues
  45 + return "" if @project.nil?
  46 +
  47 + if @project.used_default_issues_tracker?
  48 + project_issues_filter_path(@project)
  49 + else
  50 + url = Settings[:issues_tracker][@project.issues_tracker]["project_url"]
  51 + url.gsub(':project_id', @project.id.to_s)
  52 + .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
  53 + end
  54 + end
  55 +
  56 + def url_for_issue(issue_id)
  57 + return "" if @project.nil?
  58 +
  59 + if @project.used_default_issues_tracker?
  60 + url = project_issue_url project_id: @project, id: issue_id
  61 + else
  62 + url = Settings[:issues_tracker][@project.issues_tracker]["issues_url"]
  63 + url.gsub(':id', issue_id.to_s)
  64 + .gsub(':project_id', @project.id.to_s)
  65 + .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
  66 + end
  67 + end
  68 +
  69 + def title_for_issue(issue_id)
  70 + return "" if @project.nil?
  71 +
  72 + if @project.used_default_issues_tracker? && issue = @project.issues.where(id: issue_id).first
  73 + issue.title
  74 + else
  75 + ""
  76 + end
  77 + end
43 end 78 end
app/models/project.rb
@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
11 # creator_id :integer 11 # creator_id :integer
12 # default_branch :string(255) 12 # default_branch :string(255)
13 # issues_enabled :boolean default(TRUE), not null 13 # issues_enabled :boolean default(TRUE), not null
  14 +# issues_tracker :string not null
14 # wall_enabled :boolean default(TRUE), not null 15 # wall_enabled :boolean default(TRUE), not null
15 # merge_requests_enabled :boolean default(TRUE), not null 16 # merge_requests_enabled :boolean default(TRUE), not null
16 # wiki_enabled :boolean default(TRUE), not null 17 # wiki_enabled :boolean default(TRUE), not null
@@ -22,11 +23,12 @@ require "grit" @@ -22,11 +23,12 @@ require "grit"
22 23
23 class Project < ActiveRecord::Base 24 class Project < ActiveRecord::Base
24 include Gitolited 25 include Gitolited
  26 + extend Enumerize
25 27
26 class TransferError < StandardError; end 28 class TransferError < StandardError; end
27 29
28 - attr_accessible :name, :path, :description, :default_branch,  
29 - :issues_enabled, :wall_enabled, :merge_requests_enabled, 30 + attr_accessible :name, :path, :description, :default_branch, :issues_tracker,
  31 + :issues_enabled, :wall_enabled, :merge_requests_enabled, :issues_tracker_id,
30 :wiki_enabled, :public, :import_url, as: [:default, :admin] 32 :wiki_enabled, :public, :import_url, as: [:default, :admin]
31 33
32 attr_accessible :namespace_id, :creator_id, as: :admin 34 attr_accessible :namespace_id, :creator_id, as: :admin
@@ -72,6 +74,7 @@ class Project &lt; ActiveRecord::Base @@ -72,6 +74,7 @@ class Project &lt; ActiveRecord::Base
72 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } 74 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
73 validates :issues_enabled, :wall_enabled, :merge_requests_enabled, 75 validates :issues_enabled, :wall_enabled, :merge_requests_enabled,
74 :wiki_enabled, inclusion: { in: [true, false] } 76 :wiki_enabled, inclusion: { in: [true, false] }
  77 + validates :issues_tracker_id, length: { within: 0..255 }
75 78
76 validates_uniqueness_of :name, scope: :namespace_id 79 validates_uniqueness_of :name, scope: :namespace_id
77 validates_uniqueness_of :path, scope: :namespace_id 80 validates_uniqueness_of :path, scope: :namespace_id
@@ -93,6 +96,8 @@ class Project &lt; ActiveRecord::Base @@ -93,6 +96,8 @@ class Project &lt; ActiveRecord::Base
93 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } 96 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
94 scope :public_only, -> { where(public: true) } 97 scope :public_only, -> { where(public: true) }
95 98
  99 + enumerize :issues_tracker, :in => (Gitlab.config.issues_tracker.keys).append(:gitlab), :default => :gitlab
  100 +
96 class << self 101 class << self
97 def abandoned 102 def abandoned
98 project_ids = Event.select('max(created_at) as latest_date, project_id'). 103 project_ids = Event.select('max(created_at) as latest_date, project_id').
@@ -201,6 +206,22 @@ class Project &lt; ActiveRecord::Base @@ -201,6 +206,22 @@ class Project &lt; ActiveRecord::Base
201 issues.tag_counts_on(:labels) 206 issues.tag_counts_on(:labels)
202 end 207 end
203 208
  209 + def issue_exists?(issue_id)
  210 + if used_default_issues_tracker?
  211 + self.issues.where(id: issue_id).first.present?
  212 + else
  213 + true
  214 + end
  215 + end
  216 +
  217 + def used_default_issues_tracker?
  218 + self.issues_tracker == Project.issues_tracker.default_value
  219 + end
  220 +
  221 + def can_have_issues_tracker_id?
  222 + self.issues_enabled && !self.used_default_issues_tracker?
  223 + end
  224 +
204 def services 225 def services
205 [gitlab_ci_service].compact 226 [gitlab_ci_service].compact
206 end 227 end
app/views/admin/projects/_form.html.haml
@@ -31,6 +31,15 @@ @@ -31,6 +31,15 @@
31 = f.label :issues_enabled, "Issues" 31 = f.label :issues_enabled, "Issues"
32 .input= f.check_box :issues_enabled 32 .input= f.check_box :issues_enabled
33 33
  34 + - if Project.issues_tracker.values.count > 1
  35 + .clearfix
  36 + = f.label :issues_tracker, "Issues tracker", class: 'control-label'
  37 + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
  38 +
  39 + .clearfix
  40 + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
  41 + .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id?
  42 +
34 .clearfix 43 .clearfix
35 = f.label :merge_requests_enabled, "Merge Requests" 44 = f.label :merge_requests_enabled, "Merge Requests"
36 .input= f.check_box :merge_requests_enabled 45 .input= f.check_box :merge_requests_enabled
app/views/layouts/_head.html.haml
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 = stylesheet_link_tag "application" 7 = stylesheet_link_tag "application"
8 = javascript_include_tag "application" 8 = javascript_include_tag "application"
9 = csrf_meta_tags 9 = csrf_meta_tags
  10 + = include_gon
10 11
11 -# Atom feed 12 -# Atom feed
12 - if current_user 13 - if current_user
app/views/layouts/project_resource.html.haml
@@ -22,11 +22,12 @@ @@ -22,11 +22,12 @@
22 = nav_link(controller: %w(graph)) do 22 = nav_link(controller: %w(graph)) do
23 = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref) 23 = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref)
24 24
25 - - if @project.issues_enabled 25 + - if @project.issues_enabled
26 = nav_link(controller: %w(issues milestones labels)) do 26 = nav_link(controller: %w(issues milestones labels)) do
27 - = link_to project_issues_filter_path(@project) do 27 + = link_to url_for_project_issues do
28 Issues 28 Issues
29 - %span.count.issue_counter= @project.issues.opened.count 29 + - if @project.used_default_issues_tracker?
  30 + %span.count.issue_counter= @project.issues.opened.count
30 31
31 - if @project.repo_exists? && @project.merge_requests_enabled 32 - if @project.repo_exists? && @project.merge_requests_enabled
32 = nav_link(controller: :merge_requests) do 33 = nav_link(controller: :merge_requests) do
app/views/projects/_form.html.haml
@@ -24,6 +24,15 @@ @@ -24,6 +24,15 @@
24 = f.check_box :issues_enabled 24 = f.check_box :issues_enabled
25 %span.descr Lightweight issue tracking system for this project 25 %span.descr Lightweight issue tracking system for this project
26 26
  27 + - if Project.issues_tracker.values.count > 1
  28 + .control-group
  29 + = f.label :issues_tracker, "Issues tracker", class: 'control-label'
  30 + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
  31 +
  32 + .clearfix
  33 + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
  34 + .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id?
  35 +
27 .control-group 36 .control-group
28 = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label' 37 = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label'
29 .controls 38 .controls
config/gitlab.yml.example
@@ -37,6 +37,22 @@ production: &amp;base @@ -37,6 +37,22 @@ production: &amp;base
37 # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. 37 # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled.
38 # username_changing_enabled: false # default: true - User can change her username/namespace 38 # username_changing_enabled: false # default: true - User can change her username/namespace
39 39
  40 +
  41 + ## External issues trackers
  42 + issues_tracker:
  43 + redmine:
  44 + ## If not nil, link 'Issues' on project page will be replaced tp this
  45 + ## Use placeholders:
  46 + ## :project_id - Gitlab project identifier
  47 + ## :issues_tracker_id - Project Name or Id in external issue tracker
  48 + project_url: "http://redmine.sample/projects/:issues_tracker_id"
  49 + ## If not nil, links from /#\d/ entities from commit messages will replaced to this
  50 + ## Use placeholders:
  51 + ## :project_id - Gitlab project identifier
  52 + ## :issues_tracker_id - Project Name or Id in external issue tracker
  53 + ## :id - Issue id (from commit messages)
  54 + issues_url: "http://redmine.sample/issues/:id"
  55 +
40 ## Gravatar 56 ## Gravatar
41 gravatar: 57 gravatar:
42 enabled: true # Use user avatar images from Gravatar.com (default: true) 58 enabled: true # Use user avatar images from Gravatar.com (default: true)
@@ -133,6 +149,10 @@ development: @@ -133,6 +149,10 @@ development:
133 149
134 test: 150 test:
135 <<: *base 151 <<: *base
  152 + issues_tracker:
  153 + redmine:
  154 + project_url: "http://redmine/projects/:issues_tracker_id"
  155 + issues_url: "http://redmine/:project_id/:issues_tracker_id/:id"
136 156
137 staging: 157 staging:
138 <<: *base 158 <<: *base
config/initializers/1_settings.rb
@@ -42,6 +42,8 @@ Settings[&#39;omniauth&#39;] ||= Settingslogic.new({}) @@ -42,6 +42,8 @@ Settings[&#39;omniauth&#39;] ||= Settingslogic.new({})
42 Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil? 42 Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil?
43 Settings.omniauth['providers'] ||= [] 43 Settings.omniauth['providers'] ||= []
44 44
  45 +Settings['issues_tracker'] ||= {}
  46 +
45 # 47 #
46 # GitLab 48 # GitLab
47 # 49 #
db/migrate/20130123114545_add_issues_tracker_to_project.rb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +class AddIssuesTrackerToProject < ActiveRecord::Migration
  2 + def change
  3 + add_column :projects, :issues_tracker, :string, default: :gitlab, null: false
  4 + end
  5 +end
db/migrate/20130211085435_add_issues_tracker_id_to_project.rb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +class AddIssuesTrackerIdToProject < ActiveRecord::Migration
  2 + def change
  3 + add_column :projects, :issues_tracker_id, :string
  4 + end
  5 +end
@@ -106,11 +106,11 @@ ActiveRecord::Schema.define(:version =&gt; 20130220133245) do @@ -106,11 +106,11 @@ ActiveRecord::Schema.define(:version =&gt; 20130220133245) do
106 add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" 106 add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id"
107 107
108 create_table "namespaces", :force => true do |t| 108 create_table "namespaces", :force => true do |t|
109 - t.string "name", :null => false  
110 - t.string "path", :null => false  
111 - t.integer "owner_id", :null => false  
112 - t.datetime "created_at", :null => false  
113 - t.datetime "updated_at", :null => false 109 + t.string "name", :null => false
  110 + t.string "path", :null => false
  111 + t.integer "owner_id", :null => false
  112 + t.datetime "created_at", :null => false
  113 + t.datetime "updated_at", :null => false
114 t.string "type" 114 t.string "type"
115 end 115 end
116 116
@@ -152,6 +152,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130220133245) do @@ -152,6 +152,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130220133245) do
152 t.boolean "wiki_enabled", :default => true, :null => false 152 t.boolean "wiki_enabled", :default => true, :null => false
153 t.integer "namespace_id" 153 t.integer "namespace_id"
154 t.boolean "public", :default => false, :null => false 154 t.boolean "public", :default => false, :null => false
  155 + t.string "issues_tracker", :default => "gitlab", :null => false
  156 + t.string "issues_tracker_id"
155 end 157 end
156 158
157 add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" 159 add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id"
@@ -230,8 +232,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130220133245) do @@ -230,8 +232,8 @@ ActiveRecord::Schema.define(:version =&gt; 20130220133245) do
230 t.string "name" 232 t.string "name"
231 t.string "path" 233 t.string "path"
232 t.integer "owner_id" 234 t.integer "owner_id"
233 - t.datetime "created_at", :null => false  
234 - t.datetime "updated_at", :null => false 235 + t.datetime "created_at", :null => false
  236 + t.datetime "updated_at", :null => false
235 end 237 end
236 238
237 create_table "users", :force => true do |t| 239 create_table "users", :force => true do |t|
lib/gitlab/markdown.rb
@@ -25,6 +25,8 @@ module Gitlab @@ -25,6 +25,8 @@ module Gitlab
25 # >> gfm(":trollface:") 25 # >> gfm(":trollface:")
26 # => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" /> 26 # => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" />
27 module Markdown 27 module Markdown
  28 + include IssuesHelper
  29 +
28 attr_reader :html_options 30 attr_reader :html_options
29 31
30 # Public: Parse the provided text with GitLab-Flavored Markdown 32 # Public: Parse the provided text with GitLab-Flavored Markdown
@@ -163,8 +165,11 @@ module Gitlab @@ -163,8 +165,11 @@ module Gitlab
163 end 165 end
164 166
165 def reference_issue(identifier) 167 def reference_issue(identifier)
166 - if issue = @project.issues.where(id: identifier).first  
167 - link_to("##{identifier}", project_issue_url(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) 168 + if @project.issue_exists? identifier
  169 + url = url_for_issue(identifier)
  170 + title = title_for_issue(identifier)
  171 +
  172 + link_to("##{identifier}", url, html_options.merge(title: "Issue: #{title}", class: "gfm gfm-issue #{html_options[:class]}"))
168 end 173 end
169 end 174 end
170 175
spec/factories.rb
@@ -29,6 +29,11 @@ FactoryGirl.define do @@ -29,6 +29,11 @@ FactoryGirl.define do
29 creator 29 creator
30 end 30 end
31 31
  32 + factory :redmine_project, parent: :project do
  33 + issues_tracker { "redmine" }
  34 + issues_tracker_id { "project_name_in_redmine" }
  35 + end
  36 +
32 factory :group do 37 factory :group do
33 sequence(:name) { |n| "group#{n}" } 38 sequence(:name) { |n| "group#{n}" }
34 path { name.downcase.gsub(/\s/, '_') } 39 path { name.downcase.gsub(/\s/, '_') }
spec/helpers/gitlab_markdown_helper_spec.rb
@@ -2,6 +2,7 @@ require &quot;spec_helper&quot; @@ -2,6 +2,7 @@ require &quot;spec_helper&quot;
2 2
3 describe GitlabMarkdownHelper do 3 describe GitlabMarkdownHelper do
4 include ApplicationHelper 4 include ApplicationHelper
  5 + include IssuesHelper
5 6
6 let!(:project) { create(:project) } 7 let!(:project) { create(:project) }
7 8
spec/helpers/issues_helper_spec.rb 0 → 100644
@@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
  1 +require "spec_helper"
  2 +
  3 +describe IssuesHelper do
  4 + let(:project) { create :project }
  5 + let(:issue) { create :issue, project: project }
  6 + let(:ext_project) { create :redmine_project }
  7 +
  8 + describe :title_for_issue do
  9 + it "should return issue title if used internal tracker" do
  10 + @project = project
  11 + title_for_issue(issue.id).should eq issue.title
  12 + end
  13 +
  14 + it "should always return empty string if used external tracker" do
  15 + @project = ext_project
  16 + title_for_issue(rand(100)).should eq ""
  17 + end
  18 +
  19 + it "should always return empty string if project nil" do
  20 + @project = nil
  21 +
  22 + title_for_issue(rand(100)).should eq ""
  23 + end
  24 + end
  25 +
  26 + describe :url_for_project_issues do
  27 + let(:project_url) { Gitlab.config.issues_tracker.redmine.project_url}
  28 + let(:ext_expected) do
  29 + project_url.gsub(':project_id', ext_project.id.to_s)
  30 + .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
  31 + end
  32 + let(:int_expected) { polymorphic_path([project]) }
  33 +
  34 + it "should return internal path if used internal tracker" do
  35 + @project = project
  36 + url_for_project_issues.should match(int_expected)
  37 + end
  38 +
  39 + it "should return path to external tracker" do
  40 + @project = ext_project
  41 +
  42 + url_for_project_issues.should match(ext_expected)
  43 + end
  44 +
  45 + it "should return empty string if project nil" do
  46 + @project = nil
  47 +
  48 + url_for_project_issues.should eq ""
  49 + end
  50 + end
  51 +
  52 + describe :url_for_issue do
  53 + let(:issue_id) { 3 }
  54 + let(:issues_url) { Gitlab.config.issues_tracker.redmine.issues_url}
  55 + let(:ext_expected) do
  56 + issues_url.gsub(':id', issue_id.to_s)
  57 + .gsub(':project_id', ext_project.id.to_s)
  58 + .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
  59 + end
  60 + let(:int_expected) { polymorphic_path([project, issue]) }
  61 +
  62 + it "should return internal path if used internal tracker" do
  63 + @project = project
  64 + url_for_issue(issue.id).should match(int_expected)
  65 + end
  66 +
  67 + it "should return path to external tracker" do
  68 + @project = ext_project
  69 +
  70 + url_for_issue(issue_id).should match(ext_expected)
  71 + end
  72 +
  73 + it "should return empty string if project nil" do
  74 + @project = nil
  75 +
  76 + url_for_issue(issue.id).should eq ""
  77 + end
  78 + end
  79 +end
spec/models/project_spec.rb
@@ -60,6 +60,7 @@ describe Project do @@ -60,6 +60,7 @@ describe Project do
60 it { should ensure_inclusion_of(:wall_enabled).in_array([true, false]) } 60 it { should ensure_inclusion_of(:wall_enabled).in_array([true, false]) }
61 it { should ensure_inclusion_of(:merge_requests_enabled).in_array([true, false]) } 61 it { should ensure_inclusion_of(:merge_requests_enabled).in_array([true, false]) }
62 it { should ensure_inclusion_of(:wiki_enabled).in_array([true, false]) } 62 it { should ensure_inclusion_of(:wiki_enabled).in_array([true, false]) }
  63 + it { should ensure_length_of(:issues_tracker_id).is_within(0..255) }
63 64
64 it "should not allow new projects beyond user limits" do 65 it "should not allow new projects beyond user limits" do
65 project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1)) 66 project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1))
@@ -190,4 +191,57 @@ describe Project do @@ -190,4 +191,57 @@ describe Project do
190 Project.new(path: "empty").repository.should be_nil 191 Project.new(path: "empty").repository.should be_nil
191 end 192 end
192 end 193 end
  194 +
  195 + describe :issue_exists? do
  196 + let(:project) { create(:project) }
  197 + let(:existed_issue) { create(:issue, project: project) }
  198 + let(:not_existed_issue) { create(:issue) }
  199 + let(:ext_project) { create(:redmine_project) }
  200 +
  201 + it "should be true or if used internal tracker and issue exists" do
  202 + project.issue_exists?(existed_issue.id).should be_true
  203 + end
  204 +
  205 + it "should be false or if used internal tracker and issue not exists" do
  206 + project.issue_exists?(not_existed_issue.id).should be_false
  207 + end
  208 +
  209 + it "should always be true if used other tracker" do
  210 + ext_project.issue_exists?(rand(100)).should be_true
  211 + end
  212 + end
  213 +
  214 + describe :used_default_issues_tracker? do
  215 + let(:project) { create(:project) }
  216 + let(:ext_project) { create(:redmine_project) }
  217 +
  218 + it "should be true if used internal tracker" do
  219 + project.used_default_issues_tracker?.should be_true
  220 + end
  221 +
  222 + it "should be false if used other tracker" do
  223 + ext_project.used_default_issues_tracker?.should be_false
  224 + end
  225 + end
  226 +
  227 + describe :can_have_issues_tracker_id? do
  228 + let(:project) { create(:project) }
  229 + let(:ext_project) { create(:redmine_project) }
  230 +
  231 + it "should be true for projects with external issues tracker if issues enabled" do
  232 + ext_project.can_have_issues_tracker_id?.should be_true
  233 + end
  234 +
  235 + it "should be false for projects with internal issue tracker if issues enabled" do
  236 + project.can_have_issues_tracker_id?.should be_false
  237 + end
  238 +
  239 + it "should be always false if issues disbled" do
  240 + project.issues_enabled = false
  241 + ext_project.issues_enabled = false
  242 +
  243 + project.can_have_issues_tracker_id?.should be_false
  244 + ext_project.can_have_issues_tracker_id?.should be_false
  245 + end
  246 + end
193 end 247 end