Commit 9c0ea135 authored by Nick Thomas's avatar Nick Thomas

Add project templates API endpoints

parent 1063d057
---
title: Allow file templates to be requested at the project level
merge_request: 7776
author:
type: added
......@@ -142,6 +142,7 @@ module API
mount ::API::Projects
mount ::API::ProjectSnapshots
mount ::API::ProjectSnippets
mount ::API::ProjectTemplates
mount ::API::ProtectedBranches
mount ::API::ProtectedTags
mount ::API::Repositories
......
......@@ -1249,6 +1249,7 @@ module API
end
class TemplatesList < Grape::Entity
expose :key
expose :name
end
......
# frozen_string_literal: true
module API
class ProjectTemplates < Grape::API
include PaginationParams
TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses].freeze
before { authenticate_non_get! }
params do
requires :id, type: String, desc: 'The ID of a project'
requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses) of the template'
end
resource :projects do
desc 'Get a list of templates available to this project' do
detail 'This endpoint was introduced in GitLab 11.4'
end
params do
use :pagination
end
get ':id/templates/:type' do
templates = TemplateFinder
.build(params[:type], user_project)
.execute
present paginate(::Kaminari.paginate_array(templates)), with: Entities::TemplatesList
end
desc 'Download a template available to this project' do
detail 'This endpoint was introduced in GitLab 11.4'
end
params do
requires :name, type: String, desc: 'The name of the template'
optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses'
optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses'
end
get ':id/templates/:type/:name', requirements: { name: /[\w\.-]+/ } do
template = TemplateFinder
.build(params[:type], user_project, name: params[:name])
.execute
not_found!('Template') unless template.present?
template.resolve!(
project_name: params[:project].presence,
fullname: params[:fullname].presence || current_user&.name
)
if template.is_a?(::LicenseTemplate)
present template, with: Entities::License
else
present template, with: Entities::Template
end
end
end
end
end
{
"type": "object",
"required": [
"key",
"name",
"nickname",
"popular",
"html_url",
"source_url",
"description",
"conditions",
"permissions",
"limitations",
"content"
],
"properties": {
"key": { "type": "string" },
"name": { "type": "string" },
"nickname": { "type": ["null", "string"] },
"popular": { "type": "boolean" },
"html_url": { "type": ["null", "string"] },
"source_url": { "type": ["null", "string"] },
"description": { "type": ["null", "string"] },
"conditions": { "type": "array", "items": { "type": "string" } },
"permissions": { "type": "array", "items": { "type": "string" } },
"limitations": { "type": "array", "items": { "type": "string" } },
"content": { "type": "string" }
},
"additionalProperties": false
}
{
"type": "object",
"required": [
"name",
"content"
],
"properties": {
"name": { "type": "string" },
"content": { "type": "string" }
},
"additionalProperties": false
}
{
"type": "array",
"items": {
"type": "object",
"required": [
"key",
"name"
],
"properties": {
"key": { "type": "string" },
"name": { "type": "string" }
},
"additionalProperties": false
}
}
require 'spec_helper'
describe API::ProjectTemplates do
let(:public_project) { create(:project, :public) }
let(:private_project) { create(:project, :private) }
let(:developer) { create(:user) }
before do
private_project.add_developer(developer)
end
describe 'GET /projects/:id/templates/:type' do
it 'returns dockerfiles' do
get api("/projects/#{public_project.id}/templates/dockerfiles")
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response).to satisfy_one { |template| template['key'] == 'Binary' }
end
it 'returns gitignores' do
get api("/projects/#{public_project.id}/templates/gitignores")
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response).to satisfy_one { |template| template['key'] == 'Actionscript' }
end
it 'returns gitlab_ci_ymls' do
get api("/projects/#{public_project.id}/templates/gitlab_ci_ymls")
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response).to satisfy_one { |template| template['key'] == 'Android' }
end
it 'returns licenses' do
get api("/projects/#{public_project.id}/templates/licenses")
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response).to satisfy_one { |template| template['key'] == 'mit' }
end
it 'returns 400 for an unknown template type' do
get api("/projects/#{public_project.id}/templates/unknown")
expect(response).to have_gitlab_http_status(400)
end
it 'denies access to an anonymous user on a private project' do
get api("/projects/#{private_project.id}/templates/licenses")
expect(response).to have_gitlab_http_status(404)
end
it 'permits access to a developer on a private project' do
get api("/projects/#{private_project.id}/templates/licenses", developer)
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/template_list')
end
end
describe 'GET /projects/:id/templates/licenses' do
it 'returns key and name for the listed licenses' do
get api("/projects/#{public_project.id}/templates/licenses")
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/template_list')
end
end
describe 'GET /projects/:id/templates/:type/:key' do
it 'returns a specific dockerfile' do
get api("/projects/#{public_project.id}/templates/dockerfiles/Binary")
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/template')
expect(json_response['name']).to eq('Binary')
end
it 'returns a specific gitignore' do
get api("/projects/#{public_project.id}/templates/gitignores/Actionscript")
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/template')
expect(json_response['name']).to eq('Actionscript')
end
it 'returns a specific gitlab_ci_yml' do
get api("/projects/#{public_project.id}/templates/gitlab_ci_ymls/Android")
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/template')
expect(json_response['name']).to eq('Android')
end
it 'returns a specific license' do
get api("/projects/#{public_project.id}/templates/licenses/mit")
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/license')
end
it 'returns 404 for an unknown specific template' do
get api("/projects/#{public_project.id}/templates/licenses/unknown")
expect(response).to have_gitlab_http_status(404)
end
it 'denies access to an anonymous user on a private project' do
get api("/projects/#{private_project.id}/templates/licenses/mit")
expect(response).to have_gitlab_http_status(404)
end
it 'permits access to a developer on a private project' do
get api("/projects/#{private_project.id}/templates/licenses/mit", developer)
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/license')
end
end
describe 'GET /projects/:id/templates/licenses/:key' do
it 'fills placeholders in the license' do
get api("/projects/#{public_project.id}/templates/licenses/agpl-3.0"),
project: 'Project Placeholder',
fullname: 'Fullname Placeholder'
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/license')
content = json_response['content']
expect(content).to include('Project Placeholder')
expect(content).to include("Copyright (C) #{Time.now.year} Fullname Placeholder")
end
end
end
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