1# frozen_string_literal: true 2 3module API 4 class Tags < ::API::Base 5 include PaginationParams 6 7 TAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(tag_name: API::NO_SLASH_URL_PART_REGEX) 8 9 before { authorize! :download_code, user_project } 10 11 params do 12 requires :id, type: String, desc: 'The ID of a project' 13 end 14 resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do 15 desc 'Get a project repository tags' do 16 success Entities::Tag 17 end 18 params do 19 optional :sort, type: String, values: %w[asc desc], default: 'desc', 20 desc: 'Return tags sorted in updated by `asc` or `desc` order.' 21 optional :order_by, type: String, values: %w[name updated], default: 'updated', 22 desc: 'Return tags ordered by `name` or `updated` fields.' 23 optional :search, type: String, desc: 'Return list of tags matching the search criteria' 24 optional :page_token, type: String, desc: 'Name of tag to start the paginaition from' 25 use :pagination 26 end 27 get ':id/repository/tags', feature_category: :source_code_management, urgency: :low do 28 tags_finder = ::TagsFinder.new(user_project.repository, 29 sort: "#{params[:order_by]}_#{params[:sort]}", 30 search: params[:search], 31 page_token: params[:page_token], 32 per_page: params[:per_page]) 33 34 paginated_tags = Gitlab::Pagination::GitalyKeysetPager.new(self, user_project).paginate(tags_finder) 35 36 if Feature.enabled?(:api_caching_tags, user_project, type: :development) 37 present_cached paginated_tags, with: Entities::Tag, project: user_project, cache_context: -> (_tag) { user_project.cache_key } 38 else 39 present paginated_tags, with: Entities::Tag, project: user_project 40 end 41 42 rescue Gitlab::Git::InvalidPageToken => e 43 unprocessable_entity!(e.message) 44 rescue Gitlab::Git::CommandError 45 service_unavailable! 46 end 47 48 desc 'Get a single repository tag' do 49 success Entities::Tag 50 end 51 params do 52 requires :tag_name, type: String, desc: 'The name of the tag' 53 end 54 get ':id/repository/tags/:tag_name', requirements: TAG_ENDPOINT_REQUIREMENTS, feature_category: :source_code_management do 55 tag = user_project.repository.find_tag(params[:tag_name]) 56 not_found!('Tag') unless tag 57 58 present tag, with: Entities::Tag, project: user_project 59 end 60 61 desc 'Create a new repository tag' do 62 success Entities::Tag 63 end 64 params do 65 requires :tag_name, type: String, desc: 'The name of the tag' 66 requires :ref, type: String, desc: 'The commit sha or branch name' 67 optional :message, type: String, desc: 'Specifying a message creates an annotated tag' 68 end 69 post ':id/repository/tags', :release_orchestration do 70 authorize_admin_tag 71 72 result = ::Tags::CreateService.new(user_project, current_user) 73 .execute(params[:tag_name], params[:ref], params[:message]) 74 75 if result[:status] == :success 76 present result[:tag], 77 with: Entities::Tag, 78 project: user_project 79 else 80 render_api_error!(result[:message], 400) 81 end 82 end 83 84 desc 'Delete a repository tag' 85 params do 86 requires :tag_name, type: String, desc: 'The name of the tag' 87 end 88 delete ':id/repository/tags/:tag_name', requirements: TAG_ENDPOINT_REQUIREMENTS, feature_category: :source_code_management do 89 authorize_admin_tag 90 91 tag = user_project.repository.find_tag(params[:tag_name]) 92 not_found!('Tag') unless tag 93 94 commit = user_project.repository.commit(tag.dereferenced_target) 95 96 destroy_conditionally!(commit, last_updated: commit.authored_date) do 97 result = ::Tags::DestroyService.new(user_project, current_user) 98 .execute(params[:tag_name]) 99 100 if result[:status] != :success 101 render_api_error!(result[:message], result[:return_code]) 102 end 103 end 104 end 105 end 106 end 107end 108