# frozen_string_literal: true module API class Releases < ::API::Base include PaginationParams RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS .merge(tag_name: API::NO_SLASH_URL_PART_REGEX) before { authorize_read_releases! } feature_category :release_orchestration params do requires :id, type: String, desc: 'The ID of a project' end resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do desc 'Get a project releases' do detail 'This feature was introduced in GitLab 11.7.' success Entities::Release end params do use :pagination optional :order_by, type: String, values: %w[released_at created_at], default: 'released_at', desc: 'Return releases ordered by `released_at` or `created_at`.' optional :sort, type: String, values: %w[asc desc], default: 'desc', desc: 'Return releases sorted in `asc` or `desc` order.' end get ':id/releases' do releases = ::ReleasesFinder.new(user_project, current_user, declared_params.slice(:order_by, :sort)).execute present paginate(releases), with: Entities::Release, current_user: current_user end desc 'Get a single project release' do detail 'This feature was introduced in GitLab 11.7.' success Entities::Release end params do requires :tag_name, type: String, desc: 'The name of the tag', as: :tag end get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do authorize_download_code! present release, with: Entities::Release, current_user: current_user end desc 'Create a new release' do detail 'This feature was introduced in GitLab 11.7.' success Entities::Release end params do requires :tag_name, type: String, desc: 'The name of the tag', as: :tag optional :name, type: String, desc: 'The name of the release' optional :description, type: String, desc: 'The release notes' optional :ref, type: String, desc: 'The commit sha or branch name' optional :assets, type: Hash do optional :links, type: Array do requires :name, type: String, desc: 'The name of the link' requires :url, type: String, desc: 'The URL of the link' optional :filepath, type: String, desc: 'The filepath of the link' optional :link_type, type: String, desc: 'The link type, one of: "runbook", "image", "package" or "other"' end end optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones', default: [] optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.' end route_setting :authentication, job_token_allowed: true post ':id/releases' do authorize_create_release! result = ::Releases::CreateService .new(user_project, current_user, declared_params(include_missing: false)) .execute if result[:status] == :success log_release_created_audit_event(result[:release]) present result[:release], with: Entities::Release, current_user: current_user else render_api_error!(result[:message], result[:http_status]) end end desc 'Update a release' do detail 'This feature was introduced in GitLab 11.7.' success Entities::Release end params do requires :tag_name, type: String, desc: 'The name of the tag', as: :tag optional :name, type: String, desc: 'The name of the release' optional :description, type: String, desc: 'Release notes with markdown support' optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready.' optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones' end put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do authorize_update_release! result = ::Releases::UpdateService .new(user_project, current_user, declared_params(include_missing: false)) .execute if result[:status] == :success log_release_updated_audit_event log_release_milestones_updated_audit_event if result[:milestones_updated] present result[:release], with: Entities::Release, current_user: current_user else render_api_error!(result[:message], result[:http_status]) end end desc 'Delete a release' do detail 'This feature was introduced in GitLab 11.7.' success Entities::Release end params do requires :tag_name, type: String, desc: 'The name of the tag', as: :tag end delete ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do authorize_destroy_release! result = ::Releases::DestroyService .new(user_project, current_user, declared_params(include_missing: false)) .execute if result[:status] == :success present result[:release], with: Entities::Release, current_user: current_user else render_api_error!(result[:message], result[:http_status]) end end end helpers do def authorize_create_release! authorize! :create_release, user_project end def authorize_read_releases! authorize! :read_release, user_project end def authorize_read_release! authorize! :read_release, release end def authorize_update_release! authorize! :update_release, release end def authorize_destroy_release! authorize! :destroy_release, release end def authorize_download_code! authorize! :download_code, release end def authorize_create_evidence! # extended in EE end def release @release ||= user_project.releases.find_by_tag(params[:tag]) end def log_release_created_audit_event(release) # extended in EE end def log_release_updated_audit_event # extended in EE end def log_release_milestones_updated_audit_event # extended in EE end end end end API::Releases.prepend_if_ee('EE::API::Releases')