summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/actions/setup-redmine/action.yml68
-rw-r--r--.github/workflows/tests.yml85
-rw-r--r--Gemfile5
-rw-r--r--app/controllers/auto_completes_controller.rb2
-rw-r--r--app/controllers/repositories_controller.rb10
-rw-r--r--app/controllers/wiki_controller.rb1
-rw-r--r--app/helpers/application_helper.rb4
-rw-r--r--app/models/email_address.rb6
-rw-r--r--app/models/time_entry_query.rb19
-rw-r--r--app/models/user.rb4
-rw-r--r--app/views/custom_fields/index.api.rsb1
-rw-r--r--app/views/issues/_list.html.erb4
-rw-r--r--app/views/queries/_form.html.erb2
-rw-r--r--app/views/timelog/_list.html.erb4
-rw-r--r--app/views/versions/index.html.erb2
-rw-r--r--app/views/versions/show.html.erb2
-rw-r--r--app/views/workflows/edit.html.erb4
-rw-r--r--config/boot.rb16
-rw-r--r--config/routes.rb2
-rw-r--r--doc/CHANGELOG119
-rw-r--r--lib/redmine/helpers/gantt.rb10
-rw-r--r--lib/redmine/i18n.rb12
-rw-r--r--lib/redmine/version.rb2
-rw-r--r--lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb2
-rw-r--r--public/stylesheets/application.css4
-rw-r--r--public/stylesheets/responsive.css4
-rw-r--r--public/stylesheets/rtl.css2
-rw-r--r--test/application_system_test_case.rb9
-rw-r--r--test/fixtures/changesets.yml12
-rw-r--r--test/functional/attachments_controller_test.rb6
-rw-r--r--test/functional/documents_controller_test.rb4
-rw-r--r--test/functional/issues_controller_test.rb18
-rw-r--r--test/functional/queries_controller_test.rb40
-rw-r--r--test/functional/repositories_bazaar_controller_test.rb1
-rw-r--r--test/functional/repositories_controller_test.rb2
-rw-r--r--test/functional/repositories_cvs_controller_test.rb1
-rw-r--r--test/functional/repositories_git_controller_test.rb1
-rw-r--r--test/functional/repositories_mercurial_controller_test.rb2
-rw-r--r--test/functional/repositories_subversion_controller_test.rb22
-rw-r--r--test/functional/search_controller_test.rb10
-rw-r--r--test/functional/workflows_controller_test.rb39
-rw-r--r--test/integration/api_test/attachments_test.rb2
-rw-r--r--test/integration/api_test/custom_fields_test.rb2
-rw-r--r--test/integration/api_test/news_test.rb2
-rw-r--r--test/integration/attachments_test.rb10
-rw-r--r--test/integration/repositories_git_test.rb1
-rw-r--r--test/integration/routing/attachments_test.rb2
-rw-r--r--test/system/issues_test.rb13
-rw-r--r--test/system/sudo_mode_test.rb3
-rw-r--r--test/system/timelog_test.rb3
-rw-r--r--test/unit/changeset_test.rb2
-rw-r--r--test/unit/email_address_test.rb6
-rw-r--r--test/unit/lib/redmine/scm/adapters/bazaar_adapter_test.rb1
-rw-r--r--test/unit/lib/redmine/scm/adapters/cvs_adapter_test.rb1
-rw-r--r--test/unit/lib/redmine/scm/adapters/git_adapter_test.rb9
-rw-r--r--test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb8
-rw-r--r--test/unit/lib/redmine/scm/adapters/subversion_adapter_test.rb1
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb12
-rw-r--r--test/unit/member_test.rb4
-rw-r--r--test/unit/project_admin_query_test.rb1
-rw-r--r--test/unit/repository_bazaar_test.rb1
-rw-r--r--test/unit/repository_cvs_test.rb1
-rw-r--r--test/unit/repository_git_test.rb1
-rw-r--r--test/unit/repository_mercurial_test.rb9
-rw-r--r--test/unit/repository_subversion_test.rb1
-rw-r--r--test/unit/repository_test.rb10
66 files changed, 542 insertions, 127 deletions
diff --git a/.github/actions/setup-redmine/action.yml b/.github/actions/setup-redmine/action.yml
new file mode 100644
index 000000000..d637914f0
--- /dev/null
+++ b/.github/actions/setup-redmine/action.yml
@@ -0,0 +1,68 @@
+name: Setup Redmine Test Environment
+description: Composite action for setting up Redmine test environment
+
+inputs:
+ db-type:
+ description: 'Database type: postgresql, mysql2, or sqlite3. Note: postgresql and mysql2 require service containers to be defined in the workflow.'
+ required: true
+ ruby-version:
+ description: 'Ruby version to use'
+ required: true
+
+runs:
+ using: composite
+ steps:
+ - name: Install dependencies and configure environment
+ shell: bash
+ run: |
+ sudo apt-get update
+ sudo apt-get install --yes --quiet ghostscript gsfonts locales bzr cvs
+ sudo locale-gen en_US # for bazaar non ascii test
+
+ - name: Allow imagemagick to read PDF files
+ shell: bash
+ run: |
+ echo '<policymap>' > policy.xml
+ echo '<policy domain="coder" rights="read | write" pattern="PDF" />' >> policy.xml
+ echo '</policymap>' >> policy.xml
+ sudo rm /etc/ImageMagick-6/policy.xml
+ sudo mv policy.xml /etc/ImageMagick-6/policy.xml
+
+ - if: ${{ inputs.db-type == 'sqlite3' }}
+ name: Prepare test database for sqlite3
+ shell: bash
+ run: |
+ cat > config/database.yml <<EOF
+ test:
+ adapter: sqlite3
+ database: db/test.sqlite3
+ EOF
+
+ - if: ${{ inputs.db-type == 'mysql2' || inputs.db-type == 'postgresql' }}
+ name: Prepare test database for mysql2 and postgresql
+ shell: bash
+ run: |
+ cat > config/database.yml <<EOF
+ test:
+ adapter: ${{ inputs.db-type }}
+ database: redmine_test
+ username: root
+ password: root
+ host: 127.0.0.1
+ EOF
+
+ - name: Install Ruby and gems
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: ${{ inputs.ruby-version }}
+ bundler-cache: true
+
+ - name: Run prepare test environment
+ shell: bash
+ env:
+ RAILS_ENV: test
+ SCMS: subversion,git,git_utf8,filesystem,bazaar,cvs
+ run: |
+ bundle exec rake ci:about
+ bundle exec rake ci:setup
+ bundle exec rake db:environment:set
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 4d5e0e200..481cd38a1 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -46,55 +46,11 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- - name: Install dependencies and configure environment
- run: |
- sudo apt-get update
- sudo apt-get install --yes --quiet ghostscript gsfonts locales bzr cvs
- sudo locale-gen en_US # for bazaar non ascii test
-
- - name: Allow imagemagick to read PDF files
- run: |
- echo '<policymap>' > policy.xml
- echo '<policy domain="coder" rights="read | write" pattern="PDF" />' >> policy.xml
- echo '</policymap>' >> policy.xml
- sudo rm /etc/ImageMagick-6/policy.xml
- sudo mv policy.xml /etc/ImageMagick-6/policy.xml
-
- - if: ${{ matrix.db == 'sqlite3' }}
- name: Prepare test database for sqlite3
- run: |
- cat > config/database.yml <<EOF
- test:
- adapter: sqlite3
- database: db/test.sqlite3
- EOF
-
- - if: ${{ matrix.db == 'mysql2' || matrix.db == 'postgresql' }}
- name: Prepare test database for mysql2 and postgresql
- run: |
- cat > config/database.yml <<EOF
- test:
- adapter: ${{ matrix.db }}
- database: redmine_test
- username: root
- password: root
- host: 127.0.0.1
- EOF
-
- - name: Install Ruby and gems
- uses: ruby/setup-ruby@v1
+ - name: Setup Redmine test environment
+ uses: ./.github/actions/setup-redmine
with:
+ db-type: ${{ matrix.db }}
ruby-version: ${{ matrix.ruby }}
- bundler-cache: true
-
- - name: Run prepare test environment
- env:
- RAILS_ENV: test
- SCMS: subversion,git,git_utf8,filesystem,bazaar,cvs
- run: |
- bundle exec rake ci:about
- bundle exec rake ci:setup
- bundle exec rake db:environment:set
- name: Run tests
run: |
@@ -106,3 +62,38 @@ jobs:
LC_ALL: en_US.ISO8859-1
run: |
bin/rails test test/unit/repository_bazaar_test.rb
+
+ system-tests:
+ name: system test
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Redmine test environment
+ uses: ./.github/actions/setup-redmine
+ with:
+ db-type: sqlite3
+ ruby-version: '3.2'
+
+ # System tests use Chrome and ChromeDriver installed on the GitHub Actions Ubuntu image.
+ # They are generally updated to the latest stable versions.
+ - name: Display Chrome version
+ run: google-chrome --version
+
+ - name: Run system tests
+ run: bin/rails test:system
+ env:
+ GOOGLE_CHROME_OPTS_ARGS: headless,disable-gpu,no-sandbox,disable-dev-shm-usage
+ # System tests might still be a bit unstable, so for now, even if a system test fails,
+ # output the results and consider the overall test as successful.
+ continue-on-error: true
+
+ - name: Upload system test screenshots
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: system-test-screenshots
+ path: tmp/screenshots
+ if-no-files-found: ignore
diff --git a/Gemfile b/Gemfile
index 7746ece04..00dc1e933 100644
--- a/Gemfile
+++ b/Gemfile
@@ -18,7 +18,7 @@ gem 'rubyzip', '~> 2.3.0'
# Ruby Standard Gems
gem 'csv', '~> 3.2.6'
-gem 'net-imap', '~> 0.3.4'
+gem 'net-imap', '~> 0.3.9'
gem 'net-pop', '~> 0.1.2'
gem 'net-smtp', '~> 0.3.3'
gem 'rexml', require: false if Gem.ruby_version >= Gem::Version.new('3.0')
@@ -101,7 +101,7 @@ group :development do
end
group :test do
- gem "rails-dom-testing"
+ gem "rails-dom-testing", '>= 2.3.0'
gem 'mocha', '>= 2.0.1'
gem 'simplecov', '~> 0.22.0', :require => false
gem "ffi", platforms: [:mingw, :x64_mingw, :mswin]
@@ -116,6 +116,7 @@ group :test do
end
# RuboCop
gem 'rubocop', '~> 1.57.0', require: false
+ gem 'rubocop-ast', '~> 1.40.0', require: false
gem 'rubocop-performance', '~> 1.19.0', require: false
gem 'rubocop-rails', '~> 2.22.1', require: false
end
diff --git a/app/controllers/auto_completes_controller.rb b/app/controllers/auto_completes_controller.rb
index 2982447e9..77105c8e8 100644
--- a/app/controllers/auto_completes_controller.rb
+++ b/app/controllers/auto_completes_controller.rb
@@ -26,7 +26,7 @@ class AutoCompletesController < ApplicationController
status = params[:status].to_s
issue_id = params[:issue_id].to_s
- scope = Issue.cross_project_scope(@project, params[:scope]).visible
+ scope = Issue.cross_project_scope(@project, params[:scope]).includes(:tracker).visible
scope = scope.open(status == 'o') if status.present?
scope = scope.where.not(:id => issue_id.to_i) if issue_id.present?
if q.present?
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index a5ffb4451..7e129348a 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -156,7 +156,15 @@ class RepositoriesController < ApplicationController
# Force the download
send_opt = {:filename => filename_for_content_disposition(@path.split('/').last)}
send_type = Redmine::MimeType.of(@path)
- send_opt[:type] = send_type.to_s if send_type
+ case send_type
+ when nil
+ # No MIME type detected. Let Rails use the default type.
+ when 'application/javascript'
+ # Avoid ActionController::InvalidCrossOriginRequest exception by setting non-JS content type
+ send_opt[:type] = 'text/plain'
+ else
+ send_opt[:type] = send_type
+ end
send_opt[:disposition] = disposition(@path)
send_data @repository.cat(@path, @rev), send_opt
else
diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb
index 36b90da77..bcb3b0891 100644
--- a/app/controllers/wiki_controller.rb
+++ b/app/controllers/wiki_controller.rb
@@ -240,6 +240,7 @@ class WikiController < ApplicationController
# don't load text
@versions = @page.content.versions.
select("id, author_id, comments, updated_on, version").
+ preload(:author).
reorder('version DESC').
limit(@version_pages.per_page + 1).
offset(@version_pages.offset).
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 377765cbb..bebd72834 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -402,7 +402,7 @@ module ApplicationHelper
def format_changeset_comments(changeset, options={})
method = options[:short] ? :short_comments : :comments
- textilizable changeset, method, :formatting => Setting.commit_logs_formatting?
+ textilizable changeset, method, project: changeset.project, formatting: Setting.commit_logs_formatting?
end
def due_date_distance_in_words(date)
@@ -736,7 +736,7 @@ module ApplicationHelper
end
def other_formats_links(&block)
- concat('<p class="other-formats">'.html_safe + l(:label_export_to))
+ concat('<p class="other-formats hide-when-print">'.html_safe + l(:label_export_to))
yield Redmine::Views::OtherFormatsBuilder.new(self)
concat('</p>'.html_safe)
end
diff --git a/app/models/email_address.rb b/app/models/email_address.rb
index 1e7a25ee7..909221f1a 100644
--- a/app/models/email_address.rb
+++ b/app/models/email_address.rb
@@ -66,7 +66,7 @@ class EmailAddress < ActiveRecord::Base
# Returns true if domain belongs to domains list.
def self.domain_in?(domain, domains)
- domain = domain.downcase
+ domain = domain.to_s.downcase
domains = domains.to_s.split(/[\s,]+/) unless domains.is_a?(Array)
domains.reject(&:blank?).map(&:downcase).any? do |s|
s.start_with?('.') ? domain.end_with?(s) : domain == s
@@ -142,6 +142,10 @@ class EmailAddress < ActiveRecord::Base
def validate_email_domain
domain = address.partition('@').last
+ # Skip domain validation if the email does not contain a domain part,
+ # to avoid an incomplete error message like "domain not allowed ()"
+ return if domain.empty?
+
return if self.class.valid_domain?(domain)
if User.current.logged?
diff --git a/app/models/time_entry_query.rb b/app/models/time_entry_query.rb
index 3d828d2bd..9c18f73d3 100644
--- a/app/models/time_entry_query.rb
+++ b/app/models/time_entry_query.rb
@@ -152,12 +152,19 @@ class TimeEntryQuery < Query
end
def base_scope
- TimeEntry.visible.
- joins(:project, :user).
- includes(:activity).
- references(:activity).
- left_join_issue.
- where(statement)
+ scope = TimeEntry.visible
+ .joins(:project, :user)
+ .includes(:activity)
+ .references(:activity)
+ .left_join_issue
+ .where(statement)
+
+ if Redmine::Database.mysql? && ActiveRecord::Base.connection.supports_optimizer_hints?
+ # Provides MySQL with a hint to use a better join order and avoid slow response times
+ scope.optimizer_hints('JOIN_ORDER(time_entries, projects, users)')
+ else
+ scope
+ end
end
def results_scope(options={})
diff --git a/app/models/user.rb b/app/models/user.rb
index d189898dd..0f18e39e5 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -87,8 +87,8 @@ class User < Principal
:after_remove => Proc.new {|user, group| group.user_removed(user)}
has_many :changesets, :dependent => :nullify
has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
- has_one :atom_token, lambda {where "action='feeds'"}, :class_name => 'Token'
- has_one :api_token, lambda {where "action='api'"}, :class_name => 'Token'
+ has_one :atom_token, lambda {where "#{table.name}.action='feeds'"}, :class_name => 'Token'
+ has_one :api_token, lambda {where "#{table.name}.action='api'"}, :class_name => 'Token'
has_one :email_address, lambda {where :is_default => true}, :autosave => true
has_many :email_addresses, :dependent => :delete_all
belongs_to :auth_source
diff --git a/app/views/custom_fields/index.api.rsb b/app/views/custom_fields/index.api.rsb
index 9f46f89f2..d4b19d62b 100644
--- a/app/views/custom_fields/index.api.rsb
+++ b/app/views/custom_fields/index.api.rsb
@@ -15,6 +15,7 @@ api.array :custom_fields do
api.multiple field.multiple?
api.default_value field.default_value
api.visible field.visible?
+ api.editable field.editable?
values = field.possible_values_options
if values.present?
diff --git a/app/views/issues/_list.html.erb b/app/views/issues/_list.html.erb
index 74b6c94f8..92a507054 100644
--- a/app/views/issues/_list.html.erb
+++ b/app/views/issues/_list.html.erb
@@ -15,7 +15,7 @@
<% query.inline_columns.each do |column| %>
<%= column_header(query, column, query_options) %>
<% end %>
- <th class="buttons"></th>
+ <th class="buttons hide-when-print"></th>
</tr>
</thead>
<tbody>
@@ -36,7 +36,7 @@
<% query.inline_columns.each do |column| %>
<%= content_tag('td', column_content(column, issue), :class => column.css_classes) %>
<% end %>
- <td class="buttons"><%= link_to_context_menu %></td>
+ <td class="buttons hide-when-print"><%= link_to_context_menu %></td>
</tr>
<% query.block_columns.each do |column|
if (text = column_content(column, issue)) && text.present? -%>
diff --git a/app/views/queries/_form.html.erb b/app/views/queries/_form.html.erb
index 1c302fe76..75a20248a 100644
--- a/app/views/queries/_form.html.erb
+++ b/app/views/queries/_form.html.erb
@@ -30,7 +30,7 @@
<% unless @query.is_a?(ProjectQuery) %>
<p><label for="query_is_for_all"><%=l(:field_is_for_all)%></label>
- <%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, :class => (User.current.admin? ? '' : 'disable-unless-private') %></p>
+ <%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, :disabled => (!@query.new_record? && @query.project.nil?), :class => (User.current.admin? ? '' : 'disable-unless-private') %></p>
<% end %>
<% unless params[:calendar] %>
diff --git a/app/views/timelog/_list.html.erb b/app/views/timelog/_list.html.erb
index af8dd1fa5..5f22627b9 100644
--- a/app/views/timelog/_list.html.erb
+++ b/app/views/timelog/_list.html.erb
@@ -11,7 +11,7 @@
<% @query.inline_columns.each do |column| %>
<%= column_header(@query, column) %>
<% end %>
- <th></th>
+ <th class="buttons hide-when-print"></th>
</tr>
</thead>
<tbody>
@@ -36,7 +36,7 @@
<% @query.inline_columns.each do |column| %>
<%= content_tag('td', column_content(column, entry), :class => column.css_classes) %>
<% end %>
- <td class="buttons">
+ <td class="buttons hide-when-print">
<% if entry.editable_by?(User.current) -%>
<%= link_to l(:button_edit), edit_time_entry_path(entry),
:title => l(:button_edit),
diff --git a/app/views/versions/index.html.erb b/app/views/versions/index.html.erb
index 382133e93..010dea7b3 100644
--- a/app/views/versions/index.html.erb
+++ b/app/views/versions/index.html.erb
@@ -37,7 +37,7 @@
<td class="checkbox"><%= check_box_tag 'ids[]', issue.id, false, :id => nil %></td>
<td class="assigned_to"><%= assignee_avatar(issue.assigned_to, :size => 16) %></td>
<td class="subject"><%= link_to_issue(issue, :project => (@project != issue.project)) %></td>
- <td class="buttons"><%= link_to_context_menu %></td>
+ <td class="buttons hide-when-print"><%= link_to_context_menu %></td>
</tr>
<% end -%>
</table>
diff --git a/app/views/versions/show.html.erb b/app/views/versions/show.html.erb
index e17571075..3d689d093 100644
--- a/app/views/versions/show.html.erb
+++ b/app/views/versions/show.html.erb
@@ -47,7 +47,7 @@
<td class="checkbox"><%= check_box_tag 'ids[]', issue.id, false, :id => nil %></td>
<td class="assigned_to"><%= assignee_avatar(issue.assigned_to, :size => 16) %></td>
<td class="subject"><%= link_to_issue(issue, :project => (@project != issue.project)) %></td>
- <td class="buttons"><%= link_to_context_menu %></td>
+ <td class="buttons hide-when-print"><%= link_to_context_menu %></td>
</tr>
<% end %>
</table>
diff --git a/app/views/workflows/edit.html.erb b/app/views/workflows/edit.html.erb
index df4507be2..adb1996cd 100644
--- a/app/views/workflows/edit.html.erb
+++ b/app/views/workflows/edit.html.erb
@@ -40,7 +40,7 @@
<%= render :partial => 'form', :locals => {:name => 'always', :workflows => @workflows['always']} %>
<fieldset class="collapsible" style="padding: 0; margin-top: 0.5em;">
- <legend onclick="toggleFieldset(this);" class="icon icon-collapsed"><%= l(:label_additional_workflow_transitions_for_author) %></legend>
+ <legend onclick="toggleFieldset(this);" class="icon icon-<%= @workflows['author'].present? ? "expanded" : "collapsed" %>"><%= l(:label_additional_workflow_transitions_for_author) %></legend>
<div id="author_workflows" style="margin: 0.5em 0 0.5em 0;">
<%= render :partial => 'form', :locals => {:name => 'author', :workflows => @workflows['author']} %>
</div>
@@ -48,7 +48,7 @@
<%= javascript_tag "hideFieldset($('#author_workflows'))" unless @workflows['author'].present? %>
<fieldset class="collapsible" style="padding: 0;">
- <legend onclick="toggleFieldset(this);" class="icon icon-collapsed"><%= l(:label_additional_workflow_transitions_for_assignee) %></legend>
+ <legend onclick="toggleFieldset(this);" class="icon icon-<%= @workflows['assignee'].present? ? "expanded" : "collapsed" %>"><%= l(:label_additional_workflow_transitions_for_assignee) %></legend>
<div id="assignee_workflows" style="margin: 0.5em 0 0.5em 0;">
<%= render :partial => 'form', :locals => {:name => 'assignee', :workflows => @workflows['assignee']} %>
</div>
diff --git a/config/boot.rb b/config/boot.rb
index 89040bd90..75f2782ff 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -1,5 +1,21 @@
# frozen_string_literal: true
+# Rack 3.1.14 or later sets default limits of 4MB for query string bytesize
+# and 4096 for the number of query parameters. These limits are too low
+# for Redmine and can cause the following issues:
+#
+# - The low bytesize limit prevents the mail handler from processing incoming
+# emails larger than 4MB (https://www.redmine.org/issues/42962)
+# - The low parameter limit prevents saving workflows with many statuses
+# (https://www.redmine.org/issues/42875)
+#
+# See also:
+# - https://github.com/rack/rack/blob/v3.1.16/README.md#configuration
+# - https://github.com/rack/rack/blob/v3.1.16/lib/rack/query_parser.rb#L54
+# - https://github.com/rack/rack/blob/v3.1.16/lib/rack/query_parser.rb#L57
+ENV['RACK_QUERY_PARSER_BYTESIZE_LIMIT'] ||= '33554432'
+ENV['RACK_QUERY_PARSER_PARAMS_LIMIT'] ||= '65536'
+
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
diff --git a/config/routes.rb b/config/routes.rb
index d5296b3c3..0457ff1ef 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -313,7 +313,7 @@ Rails.application.routes.draw do
# additional routes for having the file name at the end of url
get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment', :format => 'html'
- get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
+ get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment', :format => 'html'
get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
resources :attachments, :only => [:show, :update, :destroy]
diff --git a/doc/CHANGELOG b/doc/CHANGELOG
index ae7ac9aaf..9fc2bdd8d 100644
--- a/doc/CHANGELOG
+++ b/doc/CHANGELOG
@@ -4,6 +4,125 @@ Redmine - project management software
Copyright (C) 2006- Jean-Philippe Lang
https://www.redmine.org/
+== 2025-07-07 v5.1.9
+
+=== [Code cleanup/refactoring]
+
+* Defect #42687: Fix random failures in several system tests with Chrome 133 and later
+* Patch #42422: Use Capybara's assert_current_path in "log_user" steps to wait for page in ApplicationSystemTestCase
+* Patch #42600: Suppress "Change your password" popup for stable system tests
+* Patch #42756: Update tests for rails-dom-testing 2.3.0 whitespace collapsing
+
+=== [Database]
+
+* Defect #42622: Joining both atom_token and api_token on the User model causes an error due to the ambiguous column name "action"
+
+=== [Email receiving]
+
+* Defect #42962: Mail handler fails to create issues from emails over 4MB on Rack >= 3.1.14
+
+=== [Gems support]
+
+* Defect #42606: RuboCop warning about deprecated `EnsureNode#body` with rubocop-ast >= 1.41
+
+=== [I18n]
+
+* Defect #42815: Limit available locales to those defined by Redmine itself no longer works
+
+=== [Issues workflow]
+
+* Defect #42875: "Page not found" error when saving workflows with many statuses on Rack >= 3.1.14
+
+=== [No category]
+
+* Patch #42688: Run system tests on GitHub CI
+
+=== [Performance]
+
+* Defect #42933: Fix N+1 query issue in Wiki history page when loading authors of Wiki content versions
+
+=== [SCM]
+
+* Defect #42839: Downloading .js files from the repository browser fails with a 422 error due to ActionController::InvalidCrossOriginRequest
+* Patch #42597: Skip some Mercurial tests when using Mercurial 5.1 or later in Redmine 6.0 or 5.1
+
+=== [Security]
+
+* Patch #42662: Require net-imap gem 0.2.5, 0.3.9, 0.4.20, 0.5.7, or later to address CVE-2025-43857
+
+=== [Text formatting]
+
+* Defect #42648: Wiki/CommonMark: Broken references for multiple footnote usage
+
+=== [UI]
+
+* Defect #42640: Query totals overlaps query buttons when an RTL language is used
+* Patch #42794: Hide irrelevant information when printing
+
+== 2025-04-20 v5.1.8
+
+=== [Administration]
+
+* Defect #42584: NoMethodError when creating a user with an invalid email address and domain restrictions are enabled
+
+=== [Attachments]
+
+* Defect #42394: Inconsistent behaviour between attachment download routes with and without filename
+
+=== [Code cleanup/refactoring]
+
+* Patch #42562: Fix random test failure in ProjectAdminQueryTest due to missing language setting
+* Patch #42572: Fix random test failure in MemberTest#test_update_roles_with_inherited_roles due to non-deterministic ordering
+
+=== [Custom fields]
+
+* Patch #41935: Add "editable" attribute in the custom fields API response
+
+=== [Gantt]
+
+* Defect #42145: MiniMagick (> 5) removed cli_path, result crash when supplied imagemagick_convert_command
+
+=== [Issues]
+
+* Defect #42458: "For all projects" checkbox should be disabled when editing an existing query in which the checkbox is already checked
+
+=== [Performance]
+
+* Defect #40728: Slow loading of global spent time list in MySQL
+* Feature #42574: Optimize autocomplete issue listing triggered by typing "##" by eager loading trackers
+
+=== [Text formatting]
+
+* Defect #42545: Commit message in issue history might be rendered in incorrect context
+
+=== [UI]
+
+* Defect #41828: In mobile view, delete relation svg icon in 'Related Issues' on an issue page, overflow text
+* Defect #41947: Collapse arrow shows the wrong direction at /workflows/edit
+* Patch #42497: Adjust the position of the news comment delete button
+* Patch #42596: Do not show user icon in add watchers modal when gravatar is disabled
+
+== 2025-03-10 v5.1.7
+
+=== [Code cleanup/refactoring]
+
+* Defect #42200: InlineAutocompleteSystemTest login test fails randomly
+* Patch #42244: Fix random failures in IssuesTest#test_bulk_copy due to StaleElementReferenceError
+
+=== [Gems support]
+
+* Defect #42245: 5.1-stable: Redmine fails to start with error: Unknown database adapter `"mysql2"` found in config/database.yml
+
+=== [No category]
+
+* Feature #30069: Use GitHub Actions as a secondary CI solution to run tests through the existing mirroring
+
+=== [Security]
+* Defect #42326: Stored Cross-Site Scripting (XSS) in macros
+* Defect #42352: ProjectQuery leaks details of private projects
+* Defect #42194: /my/account does not correctly enforce sudo mode
+* Patch #42333: Update Nokogiri to 1.18.3
+
== 2025-01-29 v5.1.6
=== [Code cleanup/refactoring]
diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb
index b31486d5d..665930bf1 100644
--- a/lib/redmine/helpers/gantt.rb
+++ b/lib/redmine/helpers/gantt.rb
@@ -396,7 +396,15 @@ module Redmine
Redmine::Configuration['rmagick_font_path'].presence
img = MiniMagick::Image.create(".#{format}", false)
if Redmine::Configuration['imagemagick_convert_command'].present?
- MiniMagick.cli_path = File.dirname(Redmine::Configuration['imagemagick_convert_command'])
+ if MiniMagick.respond_to?(:cli_path)
+ MiniMagick.cli_path = File.dirname(Redmine::Configuration['imagemagick_convert_command'])
+ else
+ Rails.logger.warn(
+ 'imagemagick_convert_command option is ignored ' \
+ 'because MiniMagick has removed the option to define a custom path for the binary. ' \
+ 'Please ensure the convert binary is available in your PATH.'
+ )
+ end
end
MiniMagick::Tool::Convert.new do |gc|
gc.size('%dx%d' % [subject_width + g_width + 1, height])
diff --git a/lib/redmine/i18n.rb b/lib/redmine/i18n.rb
index 0fe080f4b..b170d278c 100644
--- a/lib/redmine/i18n.rb
+++ b/lib/redmine/i18n.rb
@@ -162,13 +162,11 @@ module Redmine
# Custom backend based on I18n::Backend::Simple with the following changes:
# * available_locales are determined by looking at translation file names
class Backend < ::I18n::Backend::Simple
- module Implementation
- # Get available locales from the translations filenames
- def available_locales
- @available_locales ||= begin
- redmine_locales = Dir[Rails.root / 'config' / 'locales' / '*.yml'].map { |f| File.basename(f, '.yml').to_sym }
- super & redmine_locales
- end
+ # Get available locales from the translations filenames
+ def available_locales
+ @available_locales ||= begin
+ redmine_locales = Dir[Rails.root / 'config' / 'locales' / '*.yml'].map { |f| File.basename(f, '.yml').to_sym }
+ super & redmine_locales
end
end
diff --git a/lib/redmine/version.rb b/lib/redmine/version.rb
index 1c4dc4ae5..d58b83345 100644
--- a/lib/redmine/version.rb
+++ b/lib/redmine/version.rb
@@ -7,7 +7,7 @@ module Redmine
module VERSION
MAJOR = 5
MINOR = 1
- TINY = 6
+ TINY = 9
# Branch values:
# * official release: nil
diff --git a/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb b/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
index c689f6d9b..09be3b01d 100644
--- a/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
+++ b/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
@@ -86,7 +86,7 @@ module Redmine
node = env[:node]
return unless node.name == "a" || node.name == "li"
return unless node.has_attribute?("id")
- return if node.name == "a" && node["id"] =~ /\Afnref-\d+\z/
+ return if node.name == "a" && node["id"] =~ /\Afnref(-\d+){1,2}\z/
return if node.name == "li" && node["id"] =~ /\Afn-\d+\z/
node.remove_attribute("id")
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 009424993..48efa4bce 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -348,7 +348,7 @@ tr.version.closed, tr.version.closed a { color: #999; }
tr.version td.name { padding-left: 20px; }
tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; }
-tr.member td.icon-user, #principals_for_new_member .icon-user {background:transparent;}
+tr.member td.icon-user, #principals_for_new_member .icon-user, #users_for_watcher .icon-user {background:transparent;}
tr.user td {width:13%;white-space: nowrap;}
td.username, td.firstname, td.lastname, td.email {text-align:left !important;}
@@ -476,7 +476,7 @@ div.square {
.contextual {float:right; white-space: nowrap; line-height:1.4em;margin:5px 0px; padding-left: 10px; font-size:0.9em;}
.contextual .icon {padding-top: 2px; padding-bottom: 3px;}
.contextual input, .contextual select {font-size:0.9em;}
-.message .contextual { margin-top: 0; }
+.message .contextual, #comments .contextual { margin-top: 0; }
.splitcontent {overflow: auto; display: flex; flex-wrap: wrap;}
.splitcontentleft {flex: 1; margin-right: 5px;}
diff --git a/public/stylesheets/responsive.css b/public/stylesheets/responsive.css
index 482f73cf2..5180258a2 100644
--- a/public/stylesheets/responsive.css
+++ b/public/stylesheets/responsive.css
@@ -778,6 +778,10 @@
width: 100%; /* let subject have one full width column */
}
+ #issue_tree .issue:has(.buttons a) > td.subject, #relations .issue:has(.buttons a) > td.subject {
+ padding-right: 40px;
+ }
+
#issue_tree .issue > td:not(.subject), #relations .issue > td:not(.subject) {
width: 20%; /* three columns for all cells that are not subject */
}
diff --git a/public/stylesheets/rtl.css b/public/stylesheets/rtl.css
index 9cae7d2eb..e0ce7dd9a 100644
--- a/public/stylesheets/rtl.css
+++ b/public/stylesheets/rtl.css
@@ -217,7 +217,7 @@ a.remove-upload {background: url(../images/delete.png) no-repeat right 1px top 5
div.thumbnails div {margin-right:0px; margin-left:2px;}
-p.other-formats { text-align:left; }
+p.other-formats, p.query-totals { text-align:left; }
a.atom { background: url(../images/feed.png) no-repeat right 1px top 50%; padding: 2px 16px 3px 0; }
diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb
index a788f337c..7ec621ab1 100644
--- a/test/application_system_test_case.rb
+++ b/test/application_system_test_case.rb
@@ -45,6 +45,11 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driver_option.add_preference 'download.default_directory', DOWNLOADS_PATH.gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR)
driver_option.add_preference 'download.prompt_for_download', false
driver_option.add_preference 'plugins.plugins_disabled', ["Chrome PDF Viewer"]
+ # Disable "Change your password" popup shown after login due to leak detection
+ driver_option.add_preference 'profile.password_manager_leak_detection', false
+ # Disable password saving prompts
+ driver_option.add_preference 'profile.password_manager_enabled', false
+ driver_option.add_preference 'credentials_enable_service', false
end
setup do
@@ -70,13 +75,13 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
# using default browser locale which depend on system locale for "real" browsers drivers
def log_user(login, password)
visit '/my/page'
- assert_equal '/login', current_path
+ assert_current_path '/login', :ignore_query => true
within('#login-form form') do
fill_in 'username', :with => login
fill_in 'password', :with => password
find('input[name=login]').click
end
- assert_equal '/my/page', current_path
+ assert_current_path '/my/page', :ignore_query => true
end
def wait_for_ajax
diff --git a/test/fixtures/changesets.yml b/test/fixtures/changesets.yml
index 247dda375..8eaca6788 100644
--- a/test/fixtures/changesets.yml
+++ b/test/fixtures/changesets.yml
@@ -102,3 +102,15 @@ changesets_010:
user_id: 3
repository_id: 10
committer: dlopper
+changesets_011:
+ commit_date: "2025-04-07"
+ comments: |-
+ This commit references an issue and a [[wiki]] page
+ Refs #2
+ committed_on: 2025-04-07 19:00:00
+ revision: "11"
+ id: 110
+ scmid:
+ user_id: 3
+ repository_id: 10
+ committer: dlopper
diff --git a/test/functional/attachments_controller_test.rb b/test/functional/attachments_controller_test.rb
index ed12955d5..2d9599d01 100644
--- a/test/functional/attachments_controller_test.rb
+++ b/test/functional/attachments_controller_test.rb
@@ -42,7 +42,7 @@ class AttachmentsControllerTest < Redmine::ControllerTest
assert_response :success
assert_equal 'text/html', @response.media_type
- assert_select 'th.filename', :text => /issues_controller.rb\t\(révision 1484\)/
+ assert_select 'th.filename', :text => /issues_controller\.rb \(révision 1484\)/
assert_select 'td.line-code', :text => /Demande créée avec succès/
end
end
@@ -61,7 +61,7 @@ class AttachmentsControllerTest < Redmine::ControllerTest
assert_response :success
assert_equal 'text/html', @response.media_type
- assert_select 'th.filename', :text => /issues_controller.rb\t\(r\?vision 1484\)/
+ assert_select 'th.filename', :text => /issues_controller\.rb \(r\?vision 1484\)/
assert_select 'td.line-code', :text => /Demande cr\?\?e avec succ\?s/
end
end
@@ -81,7 +81,7 @@ class AttachmentsControllerTest < Redmine::ControllerTest
assert_response :success
assert_equal 'text/html', @response.media_type
- assert_select 'th.filename', :text => /issues_controller.rb\t\(révision 1484\)/
+ assert_select 'th.filename', :text => /issues_controller\.rb \(révision 1484\)/
assert_select 'td.line-code', :text => /Demande créée avec succès/
end
end
diff --git a/test/functional/documents_controller_test.rb b/test/functional/documents_controller_test.rb
index b59ecdc81..944f0b30f 100644
--- a/test/functional/documents_controller_test.rb
+++ b/test/functional/documents_controller_test.rb
@@ -113,9 +113,9 @@ class DocumentsControllerTest < Redmine::ControllerTest
# adds a long description to the first document
doc = documents(:documents_001)
doc.update(:description => <<~LOREM)
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut egestas, mi vehicula varius varius, ipsum massa fermentum orci, eget tristique ante sem vel mi. Nulla facilisi. Donec enim libero, luctus ac sagittis sit amet, vehicula sagittis magna. Duis ultrices molestie ante, eget scelerisque sem iaculis vitae. Etiam fermentum mauris vitae metus pharetra condimentum fermentum est pretium. Proin sollicitudin elementum quam quis pharetra. Aenean facilisis nunc quis elit volutpat mollis. Aenean eleifend varius euismod. Ut dolor est, congue eget dapibus eget, elementum eu odio. Integer et lectus neque, nec scelerisque nisi. EndOfLineHere
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut egestas, mi vehicula varius varius, ipsum massa fermentum orci, eget tristique ante sem vel mi. Nulla facilisi. Donec enim libero, luctus ac sagittis sit amet, vehicula sagittis magna. Duis ultrices molestie ante, eget scelerisque sem iaculis vitae. Etiam fermentum mauris vitae metus pharetra condimentum fermentum est pretium. Proin sollicitudin elementum quam quis pharetra. Aenean facilisis nunc quis elit volutpat mollis. Aenean eleifend varius euismod. Ut dolor est, congue eget dapibus eget, elementum eu odio. Integer et lectus neque, nec scelerisque nisi. EndOfLineHere
- Vestibulum non velit mi. Aliquam scelerisque libero ut nulla fringilla a sollicitudin magna rhoncus. Praesent a nunc lorem, ac porttitor eros. Sed ac diam nec neque interdum adipiscing quis quis justo. Donec arcu nunc, fringilla eu dictum at, venenatis ac sem. Vestibulum quis elit urna, ac mattis sapien. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ Vestibulum non velit mi. Aliquam scelerisque libero ut nulla fringilla a sollicitudin magna rhoncus. Praesent a nunc lorem, ac porttitor eros. Sed ac diam nec neque interdum adipiscing quis quis justo. Donec arcu nunc, fringilla eu dictum at, venenatis ac sem. Vestibulum quis elit urna, ac mattis sapien. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
LOREM
get(:index, :params => {:project_id => 'ecookbook'})
assert_response :success
diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb
index 0c687d90d..08de597d1 100644
--- a/test/functional/issues_controller_test.rb
+++ b/test/functional/issues_controller_test.rb
@@ -1736,7 +1736,7 @@ class IssuesControllerTest < Redmine::ControllerTest
assert_select 'td.last_notes[colspan="4"]', :text => 'Some notes with Redmine links: #2, r2.'
assert_select(
'td.last_notes[colspan="4"]',
- :text => 'A comment with inline image: and a reference to #1 and r2.'
+ :text => 'A comment with inline image: and a reference to #1 and r2.'
)
get(
:index,
@@ -3164,6 +3164,22 @@ class IssuesControllerTest < Redmine::ControllerTest
end
end
+ def test_show_render_changeset_comments_in_original_context
+ issue = Issue.find(9)
+ issue.changeset_ids = [110]
+ issue.save!
+
+ @request.session[:user_id] = 2
+ get :issue_tab, params: {id: issue.id, name: 'changesets', format: 'js'}, xhr: true
+
+ assert_select 'div#changeset-110' do
+ # assert_select 'div.tabs a[id=?]', 'tab-changesets', text: 'unicorns'
+ assert_select 'div.changeset-comments' do
+ assert_select 'a[href=?]', '/projects/ecookbook/wiki/Wiki', text: 'wiki'
+ end
+ end
+ end
+
def test_show_should_display_spent_time_tab_for_issue_with_time_entries
@request.session[:user_id] = 1
get :show, :params => {:id => 3}
diff --git a/test/functional/queries_controller_test.rb b/test/functional/queries_controller_test.rb
index 4ee2155ff..ab3dcf531 100644
--- a/test/functional/queries_controller_test.rb
+++ b/test/functional/queries_controller_test.rb
@@ -986,4 +986,44 @@ class QueriesControllerTest < Redmine::ControllerTest
assert_include ["Development", "10"], json
assert_include ["Inactive Activity", "14"], json
end
+
+ def test_new_query_is_for_all_checkbox_not_disabled
+ @request.session[:user_id] = 1
+ get :new
+ assert_response :success
+ # Verify that the "For all projects" checkbox is not disabled when creating a new query
+ assert_select 'input[name=query_is_for_all][type=checkbox][checked]:not([disabled])'
+ end
+
+ def test_new_project_query_is_for_all_checkbox_not_disabled
+ @request.session[:user_id] = 1
+ get(:new, :params => {:project_id => 1})
+ assert_response :success
+ # Verify that the checkbox is not disabled when creating a new query within a project
+ assert_select 'input[name=query_is_for_all][type=checkbox]:not([checked]):not([disabled])'
+ end
+
+ def test_edit_global_query_is_for_all_checkbox_disabled
+ @request.session[:user_id] = 1
+ # Create a global query (project_id = nil)
+ query = IssueQuery.create!(:name => 'test_global_query', :user_id => 1, :project_id => nil)
+
+ get(:edit, :params => {:id => query.id})
+ assert_response :success
+
+ # Verify that the "For all projects" checkbox is disabled when editing an existing global query
+ assert_select 'input[name=query_is_for_all][type=checkbox][checked][disabled]'
+ end
+
+ def test_edit_project_query_is_for_all_checkbox_not_disabled
+ @request.session[:user_id] = 1
+ # Create a project-specific query
+ query = IssueQuery.create!(:name => 'test_project_query', :user_id => 1, :project_id => 1)
+
+ get(:edit, :params => {:id => query.id})
+ assert_response :success
+
+ # Verify that the checkbox is not disabled when editing a project-specific query
+ assert_select 'input[name=query_is_for_all][type=checkbox]:not([checked]):not([disabled])'
+ end
end
diff --git a/test/functional/repositories_bazaar_controller_test.rb b/test/functional/repositories_bazaar_controller_test.rb
index 076ad7748..11f75dd06 100644
--- a/test/functional/repositories_bazaar_controller_test.rb
+++ b/test/functional/repositories_bazaar_controller_test.rb
@@ -37,6 +37,7 @@ class RepositoriesBazaarControllerTest < Redmine::RepositoryControllerTest
:log_encoding => 'UTF-8'
)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
if File.directory?(REPOSITORY_PATH)
diff --git a/test/functional/repositories_controller_test.rb b/test/functional/repositories_controller_test.rb
index 81cc28ce9..0e5786581 100644
--- a/test/functional/repositories_controller_test.rb
+++ b/test/functional/repositories_controller_test.rb
@@ -186,6 +186,7 @@ class RepositoriesControllerTest < Redmine::RepositoryControllerTest
def test_show_without_main_repository_should_display_first_repository
skip unless repository_configured?('subversion')
+ skip unless Repository::Subversion.scm_available
project = Project.find(1)
repos = project.repositories
@@ -208,6 +209,7 @@ class RepositoriesControllerTest < Redmine::RepositoryControllerTest
def test_show_should_show_diff_button_depending_on_browse_repository_permission
skip unless repository_configured?('subversion')
+ skip unless Repository::Subversion.scm_available
@request.session[:user_id] = 2
role = Role.find(1)
diff --git a/test/functional/repositories_cvs_controller_test.rb b/test/functional/repositories_cvs_controller_test.rb
index d14d62420..34d9e441c 100644
--- a/test/functional/repositories_cvs_controller_test.rb
+++ b/test/functional/repositories_cvs_controller_test.rb
@@ -40,6 +40,7 @@ class RepositoriesCvsControllerTest < Redmine::RepositoryControllerTest
:url => MODULE_NAME,
:log_encoding => 'UTF-8')
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
if File.directory?(REPOSITORY_PATH)
diff --git a/test/functional/repositories_git_controller_test.rb b/test/functional/repositories_git_controller_test.rb
index 3de0672cc..8735d599a 100644
--- a/test/functional/repositories_git_controller_test.rb
+++ b/test/functional/repositories_git_controller_test.rb
@@ -41,6 +41,7 @@ class RepositoriesGitControllerTest < Redmine::RepositoryControllerTest
:path_encoding => 'ISO-8859-1'
)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
def test_create_and_update
diff --git a/test/functional/repositories_mercurial_controller_test.rb b/test/functional/repositories_mercurial_controller_test.rb
index 96a54bde8..fb26b3193 100644
--- a/test/functional/repositories_mercurial_controller_test.rb
+++ b/test/functional/repositories_mercurial_controller_test.rb
@@ -37,6 +37,8 @@ class RepositoriesMercurialControllerTest < Redmine::RepositoryControllerTest
:path_encoding => 'ISO-8859-1'
)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
+
@diff_c_support = true
end
diff --git a/test/functional/repositories_subversion_controller_test.rb b/test/functional/repositories_subversion_controller_test.rb
index b5b4061b7..44cc0a0b4 100644
--- a/test/functional/repositories_subversion_controller_test.rb
+++ b/test/functional/repositories_subversion_controller_test.rb
@@ -34,6 +34,7 @@ class RepositoriesSubversionControllerTest < Redmine::RepositoryControllerTest
@repository = Repository::Subversion.create(:project => @project,
:url => self.class.subversion_repository_url)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
if repository_configured?('subversion')
@@ -356,6 +357,27 @@ class RepositoriesSubversionControllerTest < Redmine::RepositoryControllerTest
assert_equal "attachment; filename=\"helloworld.c\"; filename*=UTF-8''helloworld.c", @response.headers['Content-Disposition']
end
+ def test_entry_should_return_text_plain_for_js_files
+ # JavaScript files should be served as 'text/plain' instead of
+ # 'application/javascript' to avoid
+ # ActionController::InvalidCrossOriginRequest exception
+ assert_equal 0, @repository.changesets.count
+ @repository.fetch_changesets
+ @project.reload
+ assert_equal NUM_REV, @repository.changesets.count
+ get(
+ :raw,
+ :params => {
+ :id => PRJ_ID,
+ :repository_id => @repository.id,
+ :path => repository_path_hash(['subversion_test', 'foo.js'])[:param]
+ }
+ )
+ assert_response :success
+ assert_equal 'text/plain', @response.media_type
+ assert_match /attachment/, @response.headers['Content-Disposition']
+ end
+
def test_directory_entry
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
diff --git a/test/functional/search_controller_test.rb b/test/functional/search_controller_test.rb
index 2cb785d70..04ec5a05d 100644
--- a/test/functional/search_controller_test.rb
+++ b/test/functional/search_controller_test.rb
@@ -66,16 +66,18 @@ class SearchControllerTest < Redmine::ControllerTest
assert_response :success
assert_select '#search-results' do
- assert_select 'dt.issue a', :text => /Feature request #2/
+ assert_select 'dt.issue a', :text => /Bug #1/
assert_select 'dt.issue a', :text => /Bug #5/
assert_select 'dt.changeset a', :text => /Revision 1/
- assert_select 'dt.issue a', :text => /Add ingredients categories/
- assert_select 'dd', :text => /should be classified by categories/
+ assert_select 'dt.issue a', :text => /Cannot print recipes/
+ assert_select 'dd', :text => /Unable to print/
end
assert_select '#search-results-counts' do
- assert_select 'a', :text => 'Changesets (5)'
+ assert_select 'a', :text => 'Changesets (6)'
+ assert_select 'a', :text => 'Issues (5)'
+ assert_select 'a', :text => 'Projects (4)'
end
end
diff --git a/test/functional/workflows_controller_test.rb b/test/functional/workflows_controller_test.rb
index 61bb3e63b..7b7803c81 100644
--- a/test/functional/workflows_controller_test.rb
+++ b/test/functional/workflows_controller_test.rb
@@ -211,6 +211,45 @@ class WorkflowsControllerTest < Redmine::ControllerTest
assert w.assignee
end
+ def test_post_edit_with_large_number_of_statuses
+ # This test ensures that workflows with many statuses can be saved.
+ # Without setting `ENV['RACK_QUERY_PARSER_PARAMS_LIMIT']`, this raises
+ # ActionController::BadRequest exception due to exceeding the default
+ # query parameter limit of 4096.
+ WorkflowTransition.delete_all
+
+ num_statuses = 40
+ transitions_data = {}
+
+ # Allowed statuses for a new issue (status_id = 0)
+ transitions_data['0'] = {}
+ (1..num_statuses).each do |status_id|
+ transitions_data['0'][status_id.to_s] = {'always' => '1'}
+ end
+
+ # Status transitions between statuses
+ (1..num_statuses).each do |status_id_from| # rubocop:disable RuboCopStyle/CombinableLoops
+ transitions_data[status_id_from.to_s] = {}
+ (1..num_statuses).each do |status_id_to|
+ # skip self-transitions
+ next if status_id_from == status_id_to
+
+ transitions_data[status_id_from.to_s][status_id_to.to_s] = {
+ 'always' => '1', 'author' => '1', 'assignee' => '1'
+ }
+ end
+ end
+
+ assert_nothing_raised do
+ patch :update, :params => {
+ :role_id => 2,
+ :tracker_id => 1,
+ :transitions => transitions_data
+ }
+ end
+ assert_response :found
+ end
+
def test_get_permissions
get :permissions
diff --git a/test/integration/api_test/attachments_test.rb b/test/integration/api_test/attachments_test.rb
index d07e22a66..32c08a067 100644
--- a/test/integration/api_test/attachments_test.rb
+++ b/test/integration/api_test/attachments_test.rb
@@ -63,7 +63,7 @@ class Redmine::ApiTest::AttachmentsTest < Redmine::ApiTest::Base
test "GET /attachments/download/:id/:filename should deny access without credentials" do
get '/attachments/download/7/archive.zip'
- assert_response 401
+ assert_response 302
end
test "GET /attachments/thumbnail/:id should return the thumbnail" do
diff --git a/test/integration/api_test/custom_fields_test.rb b/test/integration/api_test/custom_fields_test.rb
index 0df56e59a..4fb06636e 100644
--- a/test/integration/api_test/custom_fields_test.rb
+++ b/test/integration/api_test/custom_fields_test.rb
@@ -37,6 +37,8 @@ class Redmine::ApiTest::CustomFieldsTest < Redmine::ApiTest::Base
end
assert_select 'trackers[type=array]'
assert_select 'roles[type=array]'
+ assert_select 'visible', :text => 'true'
+ assert_select 'editable', :text => 'true'
end
end
end
diff --git a/test/integration/api_test/news_test.rb b/test/integration/api_test/news_test.rb
index 485af2fc1..96c3d0742 100644
--- a/test/integration/api_test/news_test.rb
+++ b/test/integration/api_test/news_test.rb
@@ -62,7 +62,7 @@ class Redmine::ApiTest::NewsTest < Redmine::ApiTest::Base
assert_select "author[id=2][name=\"John Smith\"]"
assert_select 'title', 'eCookbook first release !'
assert_select 'summary', 'First version was released...'
- assert_select 'description', "eCookbook 1.0 has been released.\n\nVisit http://ecookbook.somenet.foo/"
+ assert_select 'description', 'eCookbook 1.0 has been released. Visit http://ecookbook.somenet.foo/'
assert_select 'created_on', News.find(1).created_on.iso8601
end
end
diff --git a/test/integration/attachments_test.rb b/test/integration/attachments_test.rb
index fc64df3ee..e0a78ca9b 100644
--- a/test/integration/attachments_test.rb
+++ b/test/integration/attachments_test.rb
@@ -267,6 +267,16 @@ class AttachmentsTest < Redmine::IntegrationTest
end
end
+ def test_unauthorized_named_download_link_should_redirect_to_login
+ with_settings login_required: '1' do
+ get "/attachments/download/1"
+ assert_redirected_to "/login?back_url=http%3A%2F%2Fwww.example.com%2Fattachments%2Fdownload%2F1"
+
+ get "/attachments/download/1/error281.txt"
+ assert_redirected_to "/login?back_url=http%3A%2F%2Fwww.example.com%2Fattachments%2Fdownload%2F1%2Ferror281.txt"
+ end
+ end
+
private
def ajax_upload(filename, content, attachment_id=1)
diff --git a/test/integration/repositories_git_test.rb b/test/integration/repositories_git_test.rb
index 20d643449..793b49458 100644
--- a/test/integration/repositories_git_test.rb
+++ b/test/integration/repositories_git_test.rb
@@ -35,6 +35,7 @@ class RepositoriesGitTest < Redmine::IntegrationTest
:path_encoding => 'ISO-8859-1'
)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
if File.directory?(REPOSITORY_PATH)
diff --git a/test/integration/routing/attachments_test.rb b/test/integration/routing/attachments_test.rb
index 15e61635b..18b411f99 100644
--- a/test/integration/routing/attachments_test.rb
+++ b/test/integration/routing/attachments_test.rb
@@ -26,7 +26,7 @@ class RoutingAttachmentsTest < Redmine::RoutingTest
should_route 'GET /attachments/1/filename.txt' => 'attachments#show', :id => '1', :filename => 'filename.txt', :format => 'html'
should_route 'GET /attachments/download/1' => 'attachments#download', :id => '1'
- should_route 'GET /attachments/download/1/filename.ext' => 'attachments#download', :id => '1', :filename => 'filename.ext'
+ should_route 'GET /attachments/download/1/filename.ext' => 'attachments#download', :id => '1', :filename => 'filename.ext', :format => 'html'
should_route 'GET /attachments/thumbnail/1' => 'attachments#thumbnail', :id => '1'
should_route 'GET /attachments/thumbnail/1/200' => 'attachments#thumbnail', :id => '1', :size => '200'
diff --git a/test/system/issues_test.rb b/test/system/issues_test.rb
index 1316c1fc9..c161538e7 100644
--- a/test/system/issues_test.rb
+++ b/test/system/issues_test.rb
@@ -34,6 +34,8 @@ class IssuesSystemTest < ApplicationSystemTestCase
find('input[name=commit]').click
end
+ assert_text /Issue #\d+ created./
+
# find created issue
issue = Issue.find_by_subject("new test issue")
assert_kind_of Issue, issue
@@ -86,6 +88,7 @@ class IssuesSystemTest < ApplicationSystemTestCase
fill_in field2.name, :with => 'CF2 value'
assert_difference 'Issue.count' do
page.first(:button, 'Create').click
+ assert_text /Issue #\d+ created./
end
issue = Issue.order('id desc').first
@@ -125,6 +128,7 @@ class IssuesSystemTest < ApplicationSystemTestCase
end
assert_difference 'Issue.count' do
find('input[name=commit]').click
+ assert_text /Issue #\d+ created./
end
issue = Issue.order('id desc').first
@@ -141,6 +145,7 @@ class IssuesSystemTest < ApplicationSystemTestCase
attach_file 'attachments[dummy][file]', Rails.root.join('test/fixtures/files/testfile.txt')
fill_in 'attachments[1][description]', :with => 'Some description'
click_on 'Create'
+ assert_text /Issue #\d+ created./
end
assert_equal 1, issue.attachments.count
assert_equal 'Some description', issue.attachments.first.description
@@ -163,6 +168,7 @@ class IssuesSystemTest < ApplicationSystemTestCase
attach_file 'attachments[dummy][file]', Rails.root.join('test/fixtures/files/testfile.txt')
fill_in 'attachments[1][description]', :with => 'Some description'
click_on 'Create'
+ assert_text /Issue #\d+ created./
end
assert_equal 1, issue.attachments.count
assert_equal 'Some description', issue.attachments.first.description
@@ -181,6 +187,7 @@ class IssuesSystemTest < ApplicationSystemTestCase
click_on 'Create'
end
click_on 'Create'
+ assert_text /Issue #\d+ created./
end
end
@@ -200,6 +207,7 @@ class IssuesSystemTest < ApplicationSystemTestCase
end
assert_difference 'Issue.count' do
click_button('Create')
+ assert_text /Issue #\d+ created./
end
issue = Issue.order('id desc').first
@@ -230,6 +238,7 @@ class IssuesSystemTest < ApplicationSystemTestCase
fill_in 'Form update CF', :with => 'CF value'
assert_no_difference 'Issue.count' do
page.first(:button, 'Submit').click
+ assert_text 'Successful update.'
end
assert page.has_css?('#flash_notice')
issue = Issue.find(1)
@@ -245,6 +254,7 @@ class IssuesSystemTest < ApplicationSystemTestCase
page.find("#issue_status_id").select("Closed")
assert_no_difference 'Issue.count' do
page.first(:button, 'Submit').click
+ assert_text 'Successful update.'
end
assert page.has_css?('#flash_notice')
assert_equal 5, issue.reload.status.id
@@ -267,7 +277,8 @@ class IssuesSystemTest < ApplicationSystemTestCase
click_on 'Submit'
- assert_equal 1, Issue.find(2).attachments.count
+ assert_text 'Successful update.'
+ assert_equal 3, Issue.find(2).attachments.count
end
test "removing issue shows confirm dialog" do
diff --git a/test/system/sudo_mode_test.rb b/test/system/sudo_mode_test.rb
index 73e755acd..307d465ff 100644
--- a/test/system/sudo_mode_test.rb
+++ b/test/system/sudo_mode_test.rb
@@ -48,7 +48,6 @@ class SudoModeSystemTest < ApplicationSystemTestCase
find('input[name=commit]').click
end
- assert_equal '/users', current_path
assert page.has_content?("Confirm your password to continue")
assert page.has_css?('form#sudo-form')
@@ -56,6 +55,8 @@ class SudoModeSystemTest < ApplicationSystemTestCase
fill_in 'Password', :with => 'admin'
click_button 'Submit'
end
+
+ assert_text /User johnpaul created./
end
end
diff --git a/test/system/timelog_test.rb b/test/system/timelog_test.rb
index 166bbe1f9..bf6f1b8d0 100644
--- a/test/system/timelog_test.rb
+++ b/test/system/timelog_test.rb
@@ -49,6 +49,8 @@ class TimelogTest < ApplicationSystemTestCase
select 'QA', :from => 'Activity'
page.first(:button, 'Submit').click
+ assert_text 'Successful update.'
+
entries = TimeEntry.where(:id => [1,2,3]).to_a
assert entries.all? {|entry| entry.hours == 8.5}
assert entries.all? {|entry| entry.activity.name == 'QA'}
@@ -89,6 +91,7 @@ class TimelogTest < ApplicationSystemTestCase
select 'Tracker', :from => 'Available Columns'
page.first('input[type=button].move-right').click
click_on 'Save'
+ assert_text 'Successful update.'
# Display the list with updated settings
visit '/time_entries'
diff --git a/test/unit/changeset_test.rb b/test/unit/changeset_test.rb
index 3eac9ba8f..dff6459b4 100644
--- a/test/unit/changeset_test.rb
+++ b/test/unit/changeset_test.rb
@@ -479,7 +479,7 @@ class ChangesetTest < ActiveSupport::TestCase
end
def test_next_nil
- changeset = Changeset.find_by_revision('10')
+ changeset = Changeset.find_by_revision('11')
assert_nil changeset.next
end
diff --git a/test/unit/email_address_test.rb b/test/unit/email_address_test.rb
index 8b47e9a1d..7576b2f4f 100644
--- a/test/unit/email_address_test.rb
+++ b/test/unit/email_address_test.rb
@@ -63,6 +63,12 @@ class EmailAddressTest < ActiveSupport::TestCase
end
end
+ def test_domain_in_should_not_raise_exception_when_domain_is_nil
+ assert_nothing_raised do
+ assert_not EmailAddress.domain_in?(nil, 'example.com')
+ end
+ end
+
def test_should_reject_invalid_email
assert_not EmailAddress.new(address: 'invalid,email@example.com').valid?
end
diff --git a/test/unit/lib/redmine/scm/adapters/bazaar_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/bazaar_adapter_test.rb
index c0bff9b1f..9d6cd6b32 100644
--- a/test/unit/lib/redmine/scm/adapters/bazaar_adapter_test.rb
+++ b/test/unit/lib/redmine/scm/adapters/bazaar_adapter_test.rb
@@ -27,6 +27,7 @@ class BazaarAdapterTest < ActiveSupport::TestCase
def setup
@adapter = Redmine::Scm::Adapters::BazaarAdapter.
new(File.join(REPOSITORY_PATH, "trunk"))
+ skip "SCM command is unavailable" unless @adapter.class.client_available
end
def test_scm_version
diff --git a/test/unit/lib/redmine/scm/adapters/cvs_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/cvs_adapter_test.rb
index 2ed9dc618..3bfe24997 100644
--- a/test/unit/lib/redmine/scm/adapters/cvs_adapter_test.rb
+++ b/test/unit/lib/redmine/scm/adapters/cvs_adapter_test.rb
@@ -27,6 +27,7 @@ class CvsAdapterTest < ActiveSupport::TestCase
if File.directory?(REPOSITORY_PATH)
def setup
@adapter = Redmine::Scm::Adapters::CvsAdapter.new(MODULE_NAME, REPOSITORY_PATH)
+ skip "SCM command is unavailable" unless @adapter.class.client_available
end
def test_scm_version
diff --git a/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb
index b7a95b635..9c48c2f2e 100644
--- a/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb
+++ b/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb
@@ -42,13 +42,6 @@ class GitAdapterTest < ActiveSupport::TestCase
WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
def setup
- adapter_class = Redmine::Scm::Adapters::GitAdapter
- assert adapter_class
- assert adapter_class.client_command
- assert_equal true, adapter_class.client_available
- assert_equal true, adapter_class.client_version_above?([1])
- assert_equal true, adapter_class.client_version_above?([1, 0])
-
@adapter =
Redmine::Scm::Adapters::GitAdapter.
new(
@@ -59,6 +52,8 @@ class GitAdapterTest < ActiveSupport::TestCase
'ISO-8859-1'
)
assert @adapter
+ skip "SCM is unavailable" unless @adapter.class.client_available
+
@char_1 = 'Ü'
@str_felix_hex = "Felix Sch\xC3\xA4fer".b
end
diff --git a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb
index d8347c6dd..3315f68ab 100644
--- a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb
+++ b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb
@@ -30,12 +30,6 @@ class MercurialAdapterTest < ActiveSupport::TestCase
if File.directory?(REPOSITORY_PATH)
def setup
- adapter_class = Redmine::Scm::Adapters::MercurialAdapter
- assert adapter_class
- assert adapter_class.client_command
- assert_equal true, adapter_class.client_available
- assert_equal true, adapter_class.client_version_above?([0, 9, 5])
-
@adapter =
Redmine::Scm::Adapters::MercurialAdapter.new(
REPOSITORY_PATH,
@@ -44,6 +38,8 @@ class MercurialAdapterTest < ActiveSupport::TestCase
nil,
'ISO-8859-1'
)
+ skip "SCM command is unavailable" unless @adapter.class.client_available
+
@diff_c_support = true
@char_1 = 'Ü'
@tag_char_1 = 'tag-Ü-00'
diff --git a/test/unit/lib/redmine/scm/adapters/subversion_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/subversion_adapter_test.rb
index fe574a4ff..edc3541d1 100644
--- a/test/unit/lib/redmine/scm/adapters/subversion_adapter_test.rb
+++ b/test/unit/lib/redmine/scm/adapters/subversion_adapter_test.rb
@@ -23,6 +23,7 @@ class SubversionAdapterTest < ActiveSupport::TestCase
if repository_configured?('subversion')
def setup
@adapter = Redmine::Scm::Adapters::SubversionAdapter.new(self.class.subversion_repository_url)
+ skip "SCM command is unavailable" unless @adapter.class.client_available
end
def test_client_version
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
index d3956e802..bf7e5655f 100644
--- a/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
@@ -47,10 +47,14 @@ if Object.const_defined?(:CommonMarker)
end
def test_should_support_footnotes
- input = %(<a href="#fn-1" id="fnref-1">foo</a>)
- assert_equal input, filter(input)
- input = %(<ol><li id="fn-1">footnote</li></ol>)
- assert_equal input, filter(input)
+ [
+ %(<a href="#fn-1" id="fnref-1">foo</a>),
+ %(<a href="#fn-1" id="fnref-1-2">foo</a>),
+ %(<ol><li id="fn-1">footnote</li></ol>),
+ ].each do |input|
+ assert_equal input, filter(input)
+ assert_equal input, filter(input)
+ end
end
def test_should_remove_invalid_ids
diff --git a/test/unit/member_test.rb b/test/unit/member_test.rb
index f92841b76..42fba4783 100644
--- a/test/unit/member_test.rb
+++ b/test/unit/member_test.rb
@@ -79,7 +79,7 @@ class MemberTest < ActiveSupport::TestCase
[1, group_a_member.member_roles.find_by(role_id: 1).id],
[1, group_b_member.member_roles.find_by(role_id: 1).id],
[2, group_b_member.member_roles.find_by(role_id: 2).id],
- ], test_user_member.member_roles.map{|r| [r.role_id, r.inherited_from]}
+ ].sort, test_user_member.member_roles.map{|r| [r.role_id, r.inherited_from]}.sort
# Verify that a new non-inherited role is added and inherited roles are maintained
test_user_member.set_editable_role_ids([3]) # Add Reporter role to test_user
@@ -88,7 +88,7 @@ class MemberTest < ActiveSupport::TestCase
[1, group_b_member.member_roles.find_by(role_id: 1).id],
[2, group_b_member.member_roles.find_by(role_id: 2).id],
[3, nil]
- ], test_user_member.member_roles.map{|r| [r.role_id, r.inherited_from]}
+ ].sort, test_user_member.member_roles.map{|r| [r.role_id, r.inherited_from]}.sort
end
def test_validate
diff --git a/test/unit/project_admin_query_test.rb b/test/unit/project_admin_query_test.rb
index 7f3945fd1..e9efceaaf 100644
--- a/test/unit/project_admin_query_test.rb
+++ b/test/unit/project_admin_query_test.rb
@@ -95,6 +95,7 @@ class ProjectAdminQueryTest < ActiveSupport::TestCase
end
def test_project_statuses_values_should_return_all_statuses
+ set_language_if_valid 'en'
q = ProjectAdminQuery.new
assert_equal [
["active", "1"],
diff --git a/test/unit/repository_bazaar_test.rb b/test/unit/repository_bazaar_test.rb
index 23f3ce48f..5fec37973 100644
--- a/test/unit/repository_bazaar_test.rb
+++ b/test/unit/repository_bazaar_test.rb
@@ -50,6 +50,7 @@ class RepositoryBazaarTest < ActiveSupport::TestCase
:log_encoding => 'UTF-8'
)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
def test_blank_path_to_repository_error_message
diff --git a/test/unit/repository_cvs_test.rb b/test/unit/repository_cvs_test.rb
index af995eac0..84d0ed80b 100644
--- a/test/unit/repository_cvs_test.rb
+++ b/test/unit/repository_cvs_test.rb
@@ -36,6 +36,7 @@ class RepositoryCvsTest < ActiveSupport::TestCase
:url => MODULE_NAME,
:log_encoding => 'UTF-8')
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
def test_blank_module_error_message
diff --git a/test/unit/repository_git_test.rb b/test/unit/repository_git_test.rb
index ec1ca5157..857be9442 100644
--- a/test/unit/repository_git_test.rb
+++ b/test/unit/repository_git_test.rb
@@ -41,6 +41,7 @@ class RepositoryGitTest < ActiveSupport::TestCase
:path_encoding => 'ISO-8859-1'
)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
def test_nondefault_repo_with_blank_identifier_destruction
diff --git a/test/unit/repository_mercurial_test.rb b/test/unit/repository_mercurial_test.rb
index 861729bac..f9a18acb4 100644
--- a/test/unit/repository_mercurial_test.rb
+++ b/test/unit/repository_mercurial_test.rb
@@ -35,6 +35,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase
:path_encoding => 'ISO-8859-1'
)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
def test_blank_path_to_repository_error_message
@@ -164,6 +165,10 @@ class RepositoryMercurialTest < ActiveSupport::TestCase
end
def test_fetch_changesets_from_scratch
+ # This test fails when using Mercurial >= 5.1 due to a change in behavior.
+ # See https://repo.mercurial-scm.org/hg/rev/0c72eddb4be5 for details.
+ skip "Test skipped because Mercurial >= 5.1 is used" if @repository.scm.class.client_version_above?([5, 1])
+
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
@@ -247,6 +252,10 @@ class RepositoryMercurialTest < ActiveSupport::TestCase
end
def test_latest_changesets
+ # This test fails when using Mercurial >= 5.1 due to a change in behavior.
+ # See https://repo.mercurial-scm.org/hg/rev/0c72eddb4be5 for details.
+ skip "Test skipped because Mercurial >= 5.1 is used" if @repository.scm.class.client_version_above?([5, 1])
+
assert_equal 0, @repository.changesets.count
@repository.fetch_changesets
@project.reload
diff --git a/test/unit/repository_subversion_test.rb b/test/unit/repository_subversion_test.rb
index 477b738d5..3794cfb05 100644
--- a/test/unit/repository_subversion_test.rb
+++ b/test/unit/repository_subversion_test.rb
@@ -30,6 +30,7 @@ class RepositorySubversionTest < ActiveSupport::TestCase
@repository = Repository::Subversion.create(:project => @project,
:url => self.class.subversion_repository_url)
assert @repository
+ skip "SCM command is unavailable" unless @repository.class.scm_available
end
def test_invalid_url
diff --git a/test/unit/repository_test.rb b/test/unit/repository_test.rb
index a02e30271..d847e1f64 100644
--- a/test/unit/repository_test.rb
+++ b/test/unit/repository_test.rb
@@ -455,7 +455,7 @@ class RepositoryTest < ActiveSupport::TestCase
def test_stats_by_author_reflect_changesets_and_changes
repository = Repository.find(10)
- expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
+ expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
assert_equal expected, repository.stats_by_author
set = Changeset.create!(
@@ -467,7 +467,7 @@ class RepositoryTest < ActiveSupport::TestCase
)
Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file1')
Change.create!(:changeset => set, :action => 'A', :path => '/path/to/file2')
- expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>5}}
+ expected = {"Dave Lopper"=>{:commits_count=>12, :changes_count=>5}}
assert_equal expected, repository.stats_by_author
end
@@ -476,7 +476,7 @@ class RepositoryTest < ActiveSupport::TestCase
# to ensure things are dynamically linked to Users
User.find_by_login("dlopper").update_attribute(:firstname, "Dave's")
repository = Repository.find(10)
- expected = {"Dave's Lopper"=>{:commits_count=>10, :changes_count=>3}}
+ expected = {"Dave's Lopper"=>{:commits_count=>11, :changes_count=>3}}
assert_equal expected, repository.stats_by_author
end
@@ -502,7 +502,7 @@ class RepositoryTest < ActiveSupport::TestCase
# with committer="dlopper <dlopper@somefoo.net>"
repository = Repository.find(10)
- expected = {"Dave Lopper"=>{:commits_count=>10, :changes_count=>3}}
+ expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
assert_equal expected, repository.stats_by_author
set = Changeset.create!(
@@ -513,7 +513,7 @@ class RepositoryTest < ActiveSupport::TestCase
:comments => 'Another commit by foo.'
)
- expected = {"Dave Lopper"=>{:commits_count=>11, :changes_count=>3}}
+ expected = {"Dave Lopper"=>{:commits_count=>12, :changes_count=>3}}
assert_equal expected, repository.stats_by_author
end