summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb2
-rw-r--r--lib/api/branches.rb2
-rw-r--r--lib/api/commit_statuses.rb4
-rw-r--r--lib/api/entities.rb43
-rw-r--r--lib/api/files.rb2
-rw-r--r--lib/api/groups.rb3
-rw-r--r--lib/api/helpers.rb8
-rw-r--r--lib/api/members.rb13
-rw-r--r--lib/api/projects.rb61
-rw-r--r--lib/api/tags.rb4
-rw-r--r--lib/api/templates.rb95
-rw-r--r--lib/api/v3/members.rb134
-rw-r--r--lib/api/v3/templates.rb122
13 files changed, 344 insertions, 149 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index eb9792680ff..06346ae822a 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -7,9 +7,11 @@ module API
version 'v3', using: :path do
mount ::API::V3::DeployKeys
mount ::API::V3::Issues
+ mount ::API::V3::Members
mount ::API::V3::MergeRequests
mount ::API::V3::Projects
mount ::API::V3::ProjectSnippets
+ mount ::API::V3::Templates
end
before { allow_access_with_scope :api }
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index be659fa4a6a..9331be1f7de 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -84,7 +84,7 @@ module API
branch = user_project.repository.find_branch(params[:branch])
not_found!("Branch") unless branch
protected_branch = user_project.protected_branches.find_by(name: branch.name)
- protected_branch.destroy if protected_branch
+ protected_branch&.destroy
present branch, with: Entities::RepoBranch, project: user_project
end
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index b6e6820c3f4..0b6076bd28c 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -46,6 +46,7 @@ module API
optional :description, type: String, desc: 'A short description of the status'
optional :name, type: String, desc: 'A string label to differentiate this status from the status of other systems. Default: "default"'
optional :context, type: String, desc: 'A string label to differentiate this status from the status of other systems. Default: "default"'
+ optional :coverage, type: Float, desc: 'The total code coverage'
end
post ':id/statuses/:sha' do
authorize! :create_commit_status, user_project
@@ -75,7 +76,8 @@ module API
name: name,
ref: ref,
target_url: params[:target_url],
- description: params[:description]
+ description: params[:description],
+ coverage: params[:coverage]
)
render_validation_error!(status) if status.invalid?
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 3a5819d1bab..232f231ddd2 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -155,10 +155,27 @@ module API
expose :shared_projects, using: Entities::Project
end
+ class RepoCommit < Grape::Entity
+ expose :id, :short_id, :title, :created_at
+ expose :parent_ids
+ expose :safe_message, as: :message
+ expose :author_name, :author_email, :authored_date
+ expose :committer_name, :committer_email, :committed_date
+ end
+
+ class RepoCommitStats < Grape::Entity
+ expose :additions, :deletions, :total
+ end
+
+ class RepoCommitDetail < RepoCommit
+ expose :stats, using: Entities::RepoCommitStats
+ expose :status
+ end
+
class RepoBranch < Grape::Entity
expose :name
- expose :commit do |repo_branch, options|
+ expose :commit, using: Entities::RepoCommit do |repo_branch, options|
options[:project].repository.commit(repo_branch.dereferenced_target)
end
@@ -193,22 +210,6 @@ module API
end
end
- class RepoCommit < Grape::Entity
- expose :id, :short_id, :title, :author_name, :author_email, :created_at
- expose :committer_name, :committer_email
- expose :safe_message, as: :message
- end
-
- class RepoCommitStats < Grape::Entity
- expose :additions, :deletions, :total
- end
-
- class RepoCommitDetail < RepoCommit
- expose :parent_ids, :committed_date, :authored_date
- expose :stats, using: Entities::RepoCommitStats
- expose :status
- end
-
class ProjectSnippet < Grape::Entity
expose :id, :title, :file_name
expose :author, using: Entities::UserBasic
@@ -367,7 +368,7 @@ module API
class CommitStatus < Grape::Entity
expose :id, :sha, :ref, :status, :name, :target_url, :description,
- :created_at, :started_at, :finished_at, :allow_failure
+ :created_at, :started_at, :finished_at, :allow_failure, :coverage
expose :author, using: Entities::UserBasic
end
@@ -380,9 +381,7 @@ module API
expose :author, using: Entities::UserBasic, if: ->(event, options) { event.author }
expose :author_username do |event, options|
- if event.author
- event.author.username
- end
+ event.author&.username
end
end
@@ -416,7 +415,7 @@ module API
end
class Namespace < Grape::Entity
- expose :id, :name, :path, :kind
+ expose :id, :name, :path, :kind, :full_path
end
class MemberAccess < Grape::Entity
diff --git a/lib/api/files.rb b/lib/api/files.rb
index c58472de578..2ecdd747c8e 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -117,7 +117,7 @@ module API
authorize! :push_code, user_project
file_params = declared_params(include_missing: false)
- result = ::Files::DeleteService.new(user_project, current_user, commit_params(file_params)).execute
+ result = ::Files::DestroyService.new(user_project, current_user, commit_params(file_params)).execute
if result[:status] == :success
status(200)
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 5c132bdd6f9..9f29c4466ab 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -143,6 +143,9 @@ module API
desc: 'Return projects sorted in ascending and descending order'
optional :simple, type: Boolean, default: false,
desc: 'Return only the ID, URL, name, and path of each project'
+ optional :owned, type: Boolean, default: false, desc: 'Limit by owned by authenticated user'
+ optional :starred, type: Boolean, default: false, desc: 'Limit by starred status'
+
use :pagination
end
get ":id/projects" do
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index dfab60f7fa5..13896dd91b9 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -256,6 +256,14 @@ module API
# project helpers
def filter_projects(projects)
+ if params[:owned]
+ projects = projects.merge(current_user.owned_projects)
+ end
+
+ if params[:starred]
+ projects = projects.merge(current_user.starred_projects)
+ end
+
if params[:search].present?
projects = projects.search(params[:search])
end
diff --git a/lib/api/members.rb b/lib/api/members.rb
index d85f1f78cd6..d1d78775c6d 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -56,16 +56,9 @@ module API
member = source.members.find_by(user_id: params[:user_id])
- # We need this explicit check because `source.add_user` doesn't
- # currently return the member created so it would return 201 even if
- # the member already existed...
- # The `source_type == 'group'` check is to ensure back-compatibility
- # but 409 behavior should be used for both project and group members in 9.0!
- conflict!('Member already exists') if source_type == 'group' && member
-
- unless member
- member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at])
- end
+ conflict!('Member already exists') if member
+
+ member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at])
if member.persisted? && member.valid?
present member.user, with: Entities::Member, member: member
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index bd4b23195ac..68c2732ec80 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -50,6 +50,8 @@ module API
optional :visibility, type: String, values: %w[public internal private],
desc: 'Limit by visibility'
optional :search, type: String, desc: 'Return list of authorized projects matching the search criteria'
+ optional :owned, type: Boolean, default: false, desc: 'Limit by owned by authenticated user'
+ optional :starred, type: Boolean, default: false, desc: 'Limit by starred status'
end
params :statistics_params do
@@ -82,62 +84,9 @@ module API
params do
use :collection_params
end
- get '/visible' do
- entity = current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails
- present_projects ProjectsFinder.new.execute(current_user), with: entity
- end
-
- desc 'Get a projects list for authenticated user' do
- success Entities::BasicProjectDetails
- end
- params do
- use :collection_params
- end
get do
- authenticate!
-
- present_projects current_user.authorized_projects,
- with: Entities::ProjectWithAccess
- end
-
- desc 'Get an owned projects list for authenticated user' do
- success Entities::BasicProjectDetails
- end
- params do
- use :collection_params
- use :statistics_params
- end
- get '/owned' do
- authenticate!
-
- present_projects current_user.owned_projects,
- with: Entities::ProjectWithAccess,
- statistics: params[:statistics]
- end
-
- desc 'Gets starred project for the authenticated user' do
- success Entities::BasicProjectDetails
- end
- params do
- use :collection_params
- end
- get '/starred' do
- authenticate!
-
- present_projects current_user.viewable_starred_projects
- end
-
- desc 'Get all projects for admin user' do
- success Entities::BasicProjectDetails
- end
- params do
- use :collection_params
- use :statistics_params
- end
- get '/all' do
- authenticated_as_admin!
-
- present_projects Project.all, with: Entities::ProjectWithAccess, statistics: params[:statistics]
+ entity = current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails
+ present_projects ProjectsFinder.new.execute(current_user), with: entity, statistics: params[:statistics]
end
desc 'Create new project' do
@@ -220,7 +169,7 @@ module API
params do
optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be forked into'
end
- post 'fork/:id' do
+ post ':id/fork' do
fork_params = declared_params(include_missing: false)
namespace_id = fork_params[:namespace]
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index 5b345db3a41..b6fd8f569a9 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -40,7 +40,7 @@ module API
post ':id/repository/tags' do
authorize_push_project
- result = CreateTagService.new(user_project, current_user).
+ result = ::Tags::CreateService.new(user_project, current_user).
execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
if result[:status] == :success
@@ -59,7 +59,7 @@ module API
delete ":id/repository/tags/:tag_name", requirements: { tag_name: /.+/ } do
authorize_push_project
- result = DeleteTagService.new(user_project, current_user).
+ result = ::Tags::DestroyService.new(user_project, current_user).
execute(params[:tag_name])
if result[:status] == :success
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index e23f99256a5..8a2d66efd89 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -24,7 +24,6 @@ module API
/[\<\{\[]
(fullname|name\sof\s(author|copyright\sowner))
[\>\}\]]/xi.freeze
- DEPRECATION_MESSAGE = ' This endpoint is deprecated and will be removed in GitLab 9.0.'.freeze
helpers do
def parsed_license_template
@@ -46,74 +45,58 @@ module API
end
end
- { "licenses" => :deprecated, "templates/licenses" => :ok }.each do |route, status|
- desc 'Get the list of the available license template' do
- detailed_desc = 'This feature was introduced in GitLab 8.7.'
- detailed_desc << DEPRECATION_MESSAGE unless status == :ok
- detail detailed_desc
- success Entities::RepoLicense
- end
- params do
- optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
- end
- get route do
- options = {
- featured: declared(params).popular.present? ? true : nil
- }
- present Licensee::License.all(options), with: Entities::RepoLicense
- end
+ desc 'Get the list of the available license template' do
+ detail 'This feature was introduced in GitLab 8.7.'
+ success ::API::Entities::RepoLicense
+ end
+ params do
+ optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
+ end
+ get "templates/licenses" do
+ options = {
+ featured: declared(params).popular.present? ? true : nil
+ }
+ present Licensee::License.all(options), with: ::API::Entities::RepoLicense
end
- { "licenses/:name" => :deprecated, "templates/licenses/:name" => :ok }.each do |route, status|
- desc 'Get the text for a specific license' do
- detailed_desc = 'This feature was introduced in GitLab 8.7.'
- detailed_desc << DEPRECATION_MESSAGE unless status == :ok
- detail detailed_desc
- success Entities::RepoLicense
- end
- params do
- requires :name, type: String, desc: 'The name of the template'
- end
- get route, requirements: { name: /[\w\.-]+/ } do
- not_found!('License') unless Licensee::License.find(declared(params).name)
+ desc 'Get the text for a specific license' do
+ detail 'This feature was introduced in GitLab 8.7.'
+ success ::API::Entities::RepoLicense
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the template'
+ end
+ get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ } do
+ not_found!('License') unless Licensee::License.find(declared(params).name)
- template = parsed_license_template
+ template = parsed_license_template
- present template, with: Entities::RepoLicense
- end
+ present template, with: ::API::Entities::RepoLicense
end
GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
klass = properties[:klass]
gitlab_version = properties[:gitlab_version]
- { template_type => :deprecated, "templates/#{template_type}" => :ok }.each do |route, status|
- desc 'Get the list of the available template' do
- detailed_desc = "This feature was introduced in GitLab #{gitlab_version}."
- detailed_desc << DEPRECATION_MESSAGE unless status == :ok
- detail detailed_desc
- success Entities::TemplatesList
- end
- get route do
- present klass.all, with: Entities::TemplatesList
- end
+ desc 'Get the list of the available template' do
+ detail "This feature was introduced in GitLab #{gitlab_version}."
+ success Entities::TemplatesList
+ end
+ get "templates/#{template_type}" do
+ present klass.all, with: Entities::TemplatesList
end
- { "#{template_type}/:name" => :deprecated, "templates/#{template_type}/:name" => :ok }.each do |route, status|
- desc 'Get the text for a specific template present in local filesystem' do
- detailed_desc = "This feature was introduced in GitLab #{gitlab_version}."
- detailed_desc << DEPRECATION_MESSAGE unless status == :ok
- detail detailed_desc
- success Entities::Template
- end
- params do
- requires :name, type: String, desc: 'The name of the template'
- end
- get route do
- new_template = klass.find(declared(params).name)
+ desc 'Get the text for a specific template present in local filesystem' do
+ detail "This feature was introduced in GitLab #{gitlab_version}."
+ success Entities::Template
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the template'
+ end
+ get "templates/#{template_type}/:name" do
+ new_template = klass.find(declared(params).name)
- render_response(template_type, new_template)
- end
+ render_response(template_type, new_template)
end
end
end
diff --git a/lib/api/v3/members.rb b/lib/api/v3/members.rb
new file mode 100644
index 00000000000..4e6cb2e3c52
--- /dev/null
+++ b/lib/api/v3/members.rb
@@ -0,0 +1,134 @@
+module API
+ module V3
+ class Members < Grape::API
+ include PaginationParams
+
+ before { authenticate! }
+
+ helpers ::API::Helpers::MembersHelpers
+
+ %w[group project].each do |source_type|
+ params do
+ requires :id, type: String, desc: "The #{source_type} ID"
+ end
+ resource source_type.pluralize do
+ desc 'Gets a list of group or project members viewable by the authenticated user.' do
+ success ::API::Entities::Member
+ end
+ params do
+ optional :query, type: String, desc: 'A query string to search for members'
+ use :pagination
+ end
+ get ":id/members" do
+ source = find_source(source_type, params[:id])
+
+ users = source.users
+ users = users.merge(User.search(params[:query])) if params[:query]
+
+ present paginate(users), with: ::API::Entities::Member, source: source
+ end
+
+ desc 'Gets a member of a group or project.' do
+ success ::API::Entities::Member
+ end
+ params do
+ requires :user_id, type: Integer, desc: 'The user ID of the member'
+ end
+ get ":id/members/:user_id" do
+ source = find_source(source_type, params[:id])
+
+ members = source.members
+ member = members.find_by!(user_id: params[:user_id])
+
+ present member.user, with: ::API::Entities::Member, member: member
+ end
+
+ desc 'Adds a member to a group or project.' do
+ success ::API::Entities::Member
+ end
+ params do
+ requires :user_id, type: Integer, desc: 'The user ID of the new member'
+ requires :access_level, type: Integer, desc: 'A valid access level (defaults: `30`, developer access level)'
+ optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY'
+ end
+ post ":id/members" do
+ source = find_source(source_type, params[:id])
+ authorize_admin_source!(source_type, source)
+
+ member = source.members.find_by(user_id: params[:user_id])
+
+ # We need this explicit check because `source.add_user` doesn't
+ # currently return the member created so it would return 201 even if
+ # the member already existed...
+ # The `source_type == 'group'` check is to ensure back-compatibility
+ # but 409 behavior should be used for both project and group members in 9.0!
+ conflict!('Member already exists') if source_type == 'group' && member
+
+ unless member
+ member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at])
+ end
+ if member.persisted? && member.valid?
+ present member.user, with: ::API::Entities::Member, member: member
+ else
+ # This is to ensure back-compatibility but 400 behavior should be used
+ # for all validation errors in 9.0!
+ render_api_error!('Access level is not known', 422) if member.errors.key?(:access_level)
+ render_validation_error!(member)
+ end
+ end
+
+ desc 'Updates a member of a group or project.' do
+ success ::API::Entities::Member
+ end
+ params do
+ requires :user_id, type: Integer, desc: 'The user ID of the new member'
+ requires :access_level, type: Integer, desc: 'A valid access level'
+ optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY'
+ end
+ put ":id/members/:user_id" do
+ source = find_source(source_type, params[:id])
+ authorize_admin_source!(source_type, source)
+
+ member = source.members.find_by!(user_id: params[:user_id])
+ attrs = attributes_for_keys [:access_level, :expires_at]
+
+ if member.update_attributes(attrs)
+ present member.user, with: ::API::Entities::Member, member: member
+ else
+ # This is to ensure back-compatibility but 400 behavior should be used
+ # for all validation errors in 9.0!
+ render_api_error!('Access level is not known', 422) if member.errors.key?(:access_level)
+ render_validation_error!(member)
+ end
+ end
+
+ desc 'Removes a user from a group or project.'
+ params do
+ requires :user_id, type: Integer, desc: 'The user ID of the member'
+ end
+ delete ":id/members/:user_id" do
+ source = find_source(source_type, params[:id])
+
+ # This is to ensure back-compatibility but find_by! should be used
+ # in that casse in 9.0!
+ member = source.members.find_by(user_id: params[:user_id])
+
+ # This is to ensure back-compatibility but this should be removed in
+ # favor of find_by! in 9.0!
+ not_found!("Member: user_id:#{params[:user_id]}") if source_type == 'group' && member.nil?
+
+ # This is to ensure back-compatibility but 204 behavior should be used
+ # for all DELETE endpoints in 9.0!
+ if member.nil?
+ { message: "Access revoked", id: params[:user_id].to_i }
+ else
+ ::Members::DestroyService.new(source, current_user, declared_params).execute
+
+ present member.user, with: ::API::Entities::Member, member: member
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/v3/templates.rb b/lib/api/v3/templates.rb
new file mode 100644
index 00000000000..4c577a8d2b7
--- /dev/null
+++ b/lib/api/v3/templates.rb
@@ -0,0 +1,122 @@
+module API
+ module V3
+ class Templates < Grape::API
+ GLOBAL_TEMPLATE_TYPES = {
+ gitignores: {
+ klass: Gitlab::Template::GitignoreTemplate,
+ gitlab_version: 8.8
+ },
+ gitlab_ci_ymls: {
+ klass: Gitlab::Template::GitlabCiYmlTemplate,
+ gitlab_version: 8.9
+ },
+ dockerfiles: {
+ klass: Gitlab::Template::DockerfileTemplate,
+ gitlab_version: 8.15
+ }
+ }.freeze
+ PROJECT_TEMPLATE_REGEX =
+ /[\<\{\[]
+ (project|description|
+ one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here
+ [\>\}\]]/xi.freeze
+ YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze
+ FULLNAME_TEMPLATE_REGEX =
+ /[\<\{\[]
+ (fullname|name\sof\s(author|copyright\sowner))
+ [\>\}\]]/xi.freeze
+ DEPRECATION_MESSAGE = ' This endpoint is deprecated and has been removed in V4.'.freeze
+
+ helpers do
+ def parsed_license_template
+ # We create a fresh Licensee::License object since we'll modify its
+ # content in place below.
+ template = Licensee::License.new(params[:name])
+
+ template.content.gsub!(YEAR_TEMPLATE_REGEX, Time.now.year.to_s)
+ template.content.gsub!(PROJECT_TEMPLATE_REGEX, params[:project]) if params[:project].present?
+
+ fullname = params[:fullname].presence || current_user.try(:name)
+ template.content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname
+ template
+ end
+
+ def render_response(template_type, template)
+ not_found!(template_type.to_s.singularize) unless template
+ present template, with: ::API::Entities::Template
+ end
+ end
+
+ { "licenses" => :deprecated, "templates/licenses" => :ok }.each do |route, status|
+ desc 'Get the list of the available license template' do
+ detailed_desc = 'This feature was introduced in GitLab 8.7.'
+ detailed_desc << DEPRECATION_MESSAGE unless status == :ok
+ detail detailed_desc
+ success ::API::Entities::RepoLicense
+ end
+ params do
+ optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
+ end
+ get route do
+ options = {
+ featured: declared(params).popular.present? ? true : nil
+ }
+ present Licensee::License.all(options), with: ::API::Entities::RepoLicense
+ end
+ end
+
+ { "licenses/:name" => :deprecated, "templates/licenses/:name" => :ok }.each do |route, status|
+ desc 'Get the text for a specific license' do
+ detailed_desc = 'This feature was introduced in GitLab 8.7.'
+ detailed_desc << DEPRECATION_MESSAGE unless status == :ok
+ detail detailed_desc
+ success ::API::Entities::RepoLicense
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the template'
+ end
+ get route, requirements: { name: /[\w\.-]+/ } do
+ not_found!('License') unless Licensee::License.find(declared(params).name)
+
+ template = parsed_license_template
+
+ present template, with: ::API::Entities::RepoLicense
+ end
+ end
+
+ GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
+ klass = properties[:klass]
+ gitlab_version = properties[:gitlab_version]
+
+ { template_type => :deprecated, "templates/#{template_type}" => :ok }.each do |route, status|
+ desc 'Get the list of the available template' do
+ detailed_desc = "This feature was introduced in GitLab #{gitlab_version}."
+ detailed_desc << DEPRECATION_MESSAGE unless status == :ok
+ detail detailed_desc
+ success ::API::Entities::TemplatesList
+ end
+ get route do
+ present klass.all, with: ::API::Entities::TemplatesList
+ end
+ end
+
+ { "#{template_type}/:name" => :deprecated, "templates/#{template_type}/:name" => :ok }.each do |route, status|
+ desc 'Get the text for a specific template present in local filesystem' do
+ detailed_desc = "This feature was introduced in GitLab #{gitlab_version}."
+ detailed_desc << DEPRECATION_MESSAGE unless status == :ok
+ detail detailed_desc
+ success ::API::Entities::Template
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the template'
+ end
+ get route do
+ new_template = klass.find(declared(params).name)
+
+ render_response(template_type, new_template)
+ end
+ end
+ end
+ end
+ end
+end