Commit d1223b8b authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'CauhxMilloy/gitlab-addStartEndMarkersForTagsSearch' into 'master'

Adding support for searching tags using '^' and '$'

See merge request gitlab-org/gitlab!19435
parents 34bf8b9f fcc6f6b5
# frozen_string_literal: true # frozen_string_literal: true
class BranchesFinder class BranchesFinder < GitRefsFinder
def initialize(repository, params = {}) def initialize(repository, params = {})
@repository = repository super(repository, params)
@params = params
end end
def execute def execute
...@@ -15,56 +14,10 @@ class BranchesFinder ...@@ -15,56 +14,10 @@ class BranchesFinder
private private
attr_reader :repository, :params
def names def names
@params[:names].presence @params[:names].presence
end end
def search
@params[:search].presence
end
def sort
@params[:sort].presence || 'name'
end
def by_search(branches)
return branches unless search
case search
when ->(v) { v.starts_with?('^') }
filter_branches_with_prefix(branches, search.slice(1..-1).upcase)
when ->(v) { v.ends_with?('$') }
filter_branches_with_suffix(branches, search.chop.upcase)
else
matches = filter_branches_by_name(branches, search.upcase)
set_exact_match_as_first_result(matches, search)
end
end
def filter_branches_with_prefix(branches, prefix)
branches.select { |branch| branch.name.upcase.starts_with?(prefix) }
end
def filter_branches_with_suffix(branches, suffix)
branches.select { |branch| branch.name.upcase.ends_with?(suffix) }
end
def filter_branches_by_name(branches, term)
branches.select { |branch| branch.name.upcase.include?(term) }
end
def set_exact_match_as_first_result(matches, term)
exact_match_index = find_exact_match_index(matches, term)
matches.insert(0, matches.delete_at(exact_match_index)) if exact_match_index
matches
end
def find_exact_match_index(matches, term)
matches.index { |branch| branch.name.casecmp(term) == 0 }
end
def by_names(branches) def by_names(branches)
return branches unless names return branches unless names
......
# frozen_string_literal: true
class GitRefsFinder
def initialize(repository, params = {})
@repository = repository
@params = params
end
protected
attr_reader :repository, :params
def search
@params[:search].presence
end
def sort
@params[:sort].presence || 'name'
end
def by_search(refs)
return refs unless search
case search
when ->(v) { v.starts_with?('^') }
filter_refs_with_prefix(refs, search.slice(1..-1))
when ->(v) { v.ends_with?('$') }
filter_refs_with_suffix(refs, search.chop)
else
matches = filter_refs_by_name(refs, search)
set_exact_match_as_first_result(matches, search)
end
end
def filter_refs_with_prefix(refs, prefix)
refs.select { |ref| ref.name.upcase.starts_with?(prefix.upcase) }
end
def filter_refs_with_suffix(refs, suffix)
refs.select { |ref| ref.name.upcase.ends_with?(suffix.upcase) }
end
def filter_refs_by_name(refs, term)
refs.select { |ref| ref.name.upcase.include?(term.upcase) }
end
def set_exact_match_as_first_result(matches, term)
exact_match_index = find_exact_match_index(matches, term)
matches.insert(0, matches.delete_at(exact_match_index)) if exact_match_index
matches
end
def find_exact_match_index(matches, term)
matches.index { |ref| ref.name.casecmp(term) == 0 }
end
end
# frozen_string_literal: true # frozen_string_literal: true
class TagsFinder class TagsFinder < GitRefsFinder
def initialize(repository, params) def initialize(repository, params)
@repository = repository super(repository, params)
@params = params
end end
def execute def execute
tags = @repository.tags_sorted_by(sort) tags = repository.tags_sorted_by(sort)
filter_by_name(tags) tags = by_search(tags)
end
private
def sort
@params[:sort].presence
end
def search
@params[:search].presence
end
def filter_by_name(tags)
if search
tags.select { |tag| tag.name.include?(search) }
else
tags tags
end end
end
end end
---
title: Adding support for searching tags using '^' and '$'
merge_request: 19435
author: Cauhx Milloy
type: added
...@@ -21,7 +21,7 @@ Parameters: ...@@ -21,7 +21,7 @@ Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
|:----------|:---------------|:---------|:------------| |:----------|:---------------|:---------|:------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user.| | `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user.|
| `search` | string | no | Return list of branches containing the search string. You can use `^term` and `term$` to find branches that begin and end with `term` respectively.| | `search` | string | no | Return list of branches containing the search string. You can use `^term` and `term$` to find branches that begin and end with `term` respectively. |
Example request: Example request:
......
...@@ -17,7 +17,7 @@ Parameters: ...@@ -17,7 +17,7 @@ Parameters:
| `id` | integer/string| yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user| | `id` | integer/string| yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user|
| `order_by` | string | no | Return tags ordered by `name` or `updated` fields. Default is `updated` | | `order_by` | string | no | Return tags ordered by `name` or `updated` fields. Default is `updated` |
| `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc` | | `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Return list of tags matching the search criteria | | `search` | string | no | Return list of tags matching the search criteria. You can use `^term` and `term$` to find tags that begin and end with `term` respectively. |
> Support for `search` was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/54401) in GitLab 11.8. > Support for `search` was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/54401) in GitLab 11.8.
......
...@@ -73,58 +73,76 @@ describe BranchesFinder do ...@@ -73,58 +73,76 @@ describe BranchesFinder do
expect(result.count).to eq(3) expect(result.count).to eq(3)
expect(result.map(&:name)).to eq(%w{csv fix lfs}) expect(result.map(&:name)).to eq(%w{csv fix lfs})
end end
end
context 'filter and sort' do it 'filters branches by name that begins with' do
it 'filters branches by name and sorts by recently_updated' do params = { search: '^feature_' }
params = { sort: 'updated_desc', search: 'feat' }
branches_finder = described_class.new(repository, params) branches_finder = described_class.new(repository, params)
result = branches_finder.execute result = branches_finder.execute
expect(result.first.name).to eq('feature_conflict') expect(result.first.name).to eq('feature_conflict')
expect(result.count).to eq(2) expect(result.count).to eq(1)
end end
it 'filters branches by name and sorts by recently_updated, with exact matches first' do it 'filters branches by name that ends with' do
params = { sort: 'updated_desc', search: 'feature' } params = { search: 'feature$' }
branches_finder = described_class.new(repository, params) branches_finder = described_class.new(repository, params)
result = branches_finder.execute result = branches_finder.execute
expect(result.first.name).to eq('feature') expect(result.first.name).to eq('feature')
expect(result.second.name).to eq('feature_conflict') expect(result.count).to eq(1)
expect(result.count).to eq(2)
end end
it 'filters branches by name and sorts by last_updated' do it 'filters branches by nonexistent name that begins with' do
params = { sort: 'updated_asc', search: 'feature' } params = { search: '^nope' }
branches_finder = described_class.new(repository, params) branches_finder = described_class.new(repository, params)
result = branches_finder.execute result = branches_finder.execute
expect(result.first.name).to eq('feature') expect(result.count).to eq(0)
expect(result.count).to eq(2)
end end
it 'filters branches by name that begins with' do it 'filters branches by nonexistent name that ends with' do
params = { search: '^feature_' } params = { search: 'nope$' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.count).to eq(0)
end
end
context 'filter and sort' do
it 'filters branches by name and sorts by recently_updated' do
params = { sort: 'updated_desc', search: 'feat' }
branches_finder = described_class.new(repository, params) branches_finder = described_class.new(repository, params)
result = branches_finder.execute result = branches_finder.execute
expect(result.first.name).to eq('feature_conflict') expect(result.first.name).to eq('feature_conflict')
expect(result.count).to eq(1) expect(result.count).to eq(2)
end end
it 'filters branches by name that ends with' do it 'filters branches by name and sorts by recently_updated, with exact matches first' do
params = { search: 'feature$' } params = { sort: 'updated_desc', search: 'feature' }
branches_finder = described_class.new(repository, params) branches_finder = described_class.new(repository, params)
result = branches_finder.execute result = branches_finder.execute
expect(result.first.name).to eq('feature') expect(result.first.name).to eq('feature')
expect(result.count).to eq(1) expect(result.second.name).to eq('feature_conflict')
expect(result.count).to eq(2)
end
it 'filters branches by name and sorts by last_updated' do
params = { sort: 'updated_asc', search: 'feature' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.first.name).to eq('feature')
expect(result.count).to eq(2)
end end
end end
end end
......
...@@ -54,6 +54,44 @@ describe TagsFinder do ...@@ -54,6 +54,44 @@ describe TagsFinder do
expect(result.count).to eq(0) expect(result.count).to eq(0)
end end
it 'filters tags by name that begins with' do
params = { search: '^v1.0' }
tags_finder = described_class.new(repository, params)
result = tags_finder.execute
expect(result.first.name).to eq('v1.0.0')
expect(result.count).to eq(1)
end
it 'filters tags by name that ends with' do
params = { search: '0.0$' }
tags_finder = described_class.new(repository, params)
result = tags_finder.execute
expect(result.first.name).to eq('v1.0.0')
expect(result.count).to eq(1)
end
it 'filters tags by nonexistent name that begins with' do
params = { search: '^nope' }
tags_finder = described_class.new(repository, params)
result = tags_finder.execute
expect(result.count).to eq(0)
end
it 'filters tags by nonexistent name that ends with' do
params = { search: 'nope$' }
tags_finder = described_class.new(repository, params)
result = tags_finder.execute
expect(result.count).to eq(0)
end
end end
context 'filter and sort' do context 'filter and sort' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment