diff --git a/app/models/repository.rb b/app/models/repository.rb index 28f5fc28b8c..0c50d05bd96 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -686,7 +686,9 @@ class Repository def tags_sorted_by(value) case value - when 'name' + when 'name_asc' + VersionSorter.sort(tags) { |tag| tag.name } + when 'name_desc' VersionSorter.rsort(tags) { |tag| tag.name } when 'updated_desc' tags_sorted_by_committed_date.reverse diff --git a/changelogs/unreleased/40509_sorting_tags_api.yml b/changelogs/unreleased/40509_sorting_tags_api.yml new file mode 100644 index 00000000000..38b198d0fe3 --- /dev/null +++ b/changelogs/unreleased/40509_sorting_tags_api.yml @@ -0,0 +1,5 @@ +--- +title: add support for sorting in tags api +merge_request: 15772 +author: haseebeqx +type: added diff --git a/doc/api/tags.md b/doc/api/tags.md index bebe6536b6e..fa25dc76452 100644 --- a/doc/api/tags.md +++ b/doc/api/tags.md @@ -12,7 +12,11 @@ GET /projects/:id/repository/tags Parameters: -- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `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` | +| `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc` | ```json [ diff --git a/lib/api/tags.rb b/lib/api/tags.rb index 0d394a7b441..5e0afc6a7e4 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -14,10 +14,15 @@ module API success Entities::Tag end params do + optional :sort, type: String, values: %w[asc desc], default: 'desc', + desc: 'Return tags sorted in updated by `asc` or `desc` order.' + optional :order_by, type: String, values: %w[name updated], default: 'updated', + desc: 'Return tags ordered by `name` or `updated` fields.' use :pagination end get ':id/repository/tags' do - tags = ::Kaminari.paginate_array(user_project.repository.tags.sort_by(&:name).reverse) + tags = ::Kaminari.paginate_array(::TagsFinder.new(user_project.repository, sort: "#{params[:order_by]}_#{params[:sort]}").execute) + present paginate(tags), with: Entities::Tag, project: user_project end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 2c0d4db3307..f0661b0a972 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -59,12 +59,18 @@ describe Repository do end describe 'tags_sorted_by' do - context 'name' do - subject { repository.tags_sorted_by('name').map(&:name) } + context 'name_desc' do + subject { repository.tags_sorted_by('name_desc').map(&:name) } it { is_expected.to eq(['v1.1.0', 'v1.0.0']) } end + context 'name_asc' do + subject { repository.tags_sorted_by('name_asc').map(&:name) } + + it { is_expected.to eq(['v1.0.0', 'v1.1.0']) } + end + context 'updated' do let(:tag_a) { repository.find_tag('v1.0.0') } let(:tag_b) { repository.find_tag('v1.1.0') } diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index 0bf7863bdc8..e2b19ad59f9 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -16,6 +16,44 @@ describe API::Tags do describe 'GET /projects/:id/repository/tags' do let(:route) { "/projects/#{project_id}/repository/tags" } + context 'sorting' do + let(:current_user) { user } + + it 'sorts by descending order by default' do + get api(route, current_user) + + desc_order_tags = project.repository.tags.sort_by { |tag| tag.dereferenced_target.committed_date } + desc_order_tags.reverse!.map! { |tag| tag.dereferenced_target.id } + + expect(json_response.map { |tag| tag['commit']['id'] }).to eq(desc_order_tags) + end + + it 'sorts by ascending order if specified' do + get api("#{route}?sort=asc", current_user) + + asc_order_tags = project.repository.tags.sort_by { |tag| tag.dereferenced_target.committed_date } + asc_order_tags.map! { |tag| tag.dereferenced_target.id } + + expect(json_response.map { |tag| tag['commit']['id'] }).to eq(asc_order_tags) + end + + it 'sorts by name in descending order when requested' do + get api("#{route}?order_by=name", current_user) + + ordered_by_name = project.repository.tags.map { |tag| tag.name }.sort.reverse + + expect(json_response.map { |tag| tag['name'] }).to eq(ordered_by_name) + end + + it 'sorts by name in ascending order when requested' do + get api("#{route}?order_by=name&sort=asc", current_user) + + ordered_by_name = project.repository.tags.map { |tag| tag.name }.sort + + expect(json_response.map { |tag| tag['name'] }).to eq(ordered_by_name) + end + end + shared_examples_for 'repository tags' do it 'returns the repository tags' do get api(route, current_user)