diff options
author | Robert Speicher <robert@gitlab.com> | 2016-06-17 00:18:10 +0000 |
---|---|---|
committer | Robert Speicher <robert@gitlab.com> | 2016-06-17 00:18:10 +0000 |
commit | 6300936b679a182d79f6de917d1fdfe9ee57cbc9 (patch) | |
tree | d144a7006efac7e153bf730bffb4d5bbf49d8e3f | |
parent | 88c7b7ae961dc37d43ca29263d242241ce77efdb (diff) | |
parent | 425987861530c9c0fb7fe618d7f4bab017a80253 (diff) | |
download | gitlab-ce-6300936b679a182d79f6de917d1fdfe9ee57cbc9.tar.gz |
Merge branch 'fix-project-find-with-namespace-order' into 'master'
Fixed ordering in Project.find_with_namespace
This MR fixes the ordering of `Project.find_with_namespace` to ensure that it returns rows that match literally first.
Closes #18603
See merge request !4682
-rw-r--r-- | app/models/project.rb | 18 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 18 |
2 files changed, 34 insertions, 2 deletions
diff --git a/app/models/project.rb b/app/models/project.rb index 0bb815e64e7..8eef22356e2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -262,7 +262,23 @@ class Project < ActiveRecord::Base # # Returns a Project, or nil if no project could be found. def find_with_namespace(path) - where_paths_in([path]).reorder(nil).take + namespace_path, project_path = path.split('/', 2) + + return unless namespace_path && project_path + + namespace_path = connection.quote(namespace_path) + project_path = connection.quote(project_path) + + # On MySQL we want to ensure the ORDER BY uses a case-sensitive match so + # any literal matches come first, for this we have to use "BINARY". + # Without this there's still no guarantee in what order MySQL will return + # rows. + binary = Gitlab::Database.mysql? ? 'BINARY' : '' + + order_sql = "(CASE WHEN #{binary} namespaces.path = #{namespace_path} " \ + "AND #{binary} projects.path = #{project_path} THEN 0 ELSE 1 END)" + + where_paths_in([path]).reorder(order_sql).take end # Builds a relation to find multiple projects by their full paths. diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index fedab1f913b..53c8408633c 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -220,7 +220,7 @@ describe Project, models: true do end end - describe :find_with_namespace do + describe '.find_with_namespace' do context 'with namespace' do before do @group = create :group, name: 'gitlab' @@ -231,6 +231,22 @@ describe Project, models: true do it { expect(Project.find_with_namespace('GitLab/GitlabHQ')).to eq(@project) } it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil } end + + context 'when multiple projects using a similar name exist' do + let(:group) { create(:group, name: 'gitlab') } + + let!(:project1) do + create(:empty_project, name: 'gitlab1', path: 'gitlab', namespace: group) + end + + let!(:project2) do + create(:empty_project, name: 'gitlab2', path: 'GITLAB', namespace: group) + end + + it 'returns the row where the path matches literally' do + expect(Project.find_with_namespace('gitlab/GITLAB')).to eq(project2) + end + end end describe :to_param do |