Commit e1f77b9be071fac9f57e85b2f3853d2f333aeaab
Exists in
master
and in
4 other branches
Merge branch 'link-to-issue-tracker' of https://github.com/Undev/gitlabhq into U…
…ndev-link-to-issue-tracker Conflicts: Gemfile.lock
Showing
20 changed files
with
299 additions
and
14 deletions
Show diff stats
Gemfile
@@ -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 |
Gemfile.lock
@@ -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 < ActiveRecord::Base | @@ -72,6 +74,7 @@ class Project < 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 < ActiveRecord::Base | @@ -93,6 +96,8 @@ class Project < 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 < ActiveRecord::Base | @@ -201,6 +206,22 @@ class Project < 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: &base | @@ -37,6 +37,22 @@ production: &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['omniauth'] ||= Settingslogic.new({}) | @@ -42,6 +42,8 @@ Settings['omniauth'] ||= 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
db/migrate/20130211085435_add_issues_tracker_id_to_project.rb
0 → 100644
db/schema.rb
@@ -106,11 +106,11 @@ ActiveRecord::Schema.define(:version => 20130220133245) do | @@ -106,11 +106,11 @@ ActiveRecord::Schema.define(:version => 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 => 20130220133245) do | @@ -152,6 +152,8 @@ ActiveRecord::Schema.define(:version => 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 => 20130220133245) do | @@ -230,8 +232,8 @@ ActiveRecord::Schema.define(:version => 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 "spec_helper" | @@ -2,6 +2,7 @@ require "spec_helper" | ||
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 |
@@ -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 |