Commit f1733b1e authored by Michael Kozono's avatar Michael Kozono

Merge branch '23664-description-templates-api' into 'master'

Add API support for getting description templates

Closes https://gitlab.com/gitlab-org/gitlab/-/issues/23664

See merge request gitlab-org/gitlab!37890
parents 042b8730 a84434ae
...@@ -7,7 +7,9 @@ class TemplateFinder ...@@ -7,7 +7,9 @@ class TemplateFinder
dockerfiles: ::Gitlab::Template::DockerfileTemplate, dockerfiles: ::Gitlab::Template::DockerfileTemplate,
gitignores: ::Gitlab::Template::GitignoreTemplate, gitignores: ::Gitlab::Template::GitignoreTemplate,
gitlab_ci_ymls: ::Gitlab::Template::GitlabCiYmlTemplate, gitlab_ci_ymls: ::Gitlab::Template::GitlabCiYmlTemplate,
metrics_dashboard_ymls: ::Gitlab::Template::MetricsDashboardTemplate metrics_dashboard_ymls: ::Gitlab::Template::MetricsDashboardTemplate,
issues: ::Gitlab::Template::IssueTemplate,
merge_requests: ::Gitlab::Template::MergeRequestTemplate
).freeze ).freeze
class << self class << self
...@@ -35,9 +37,9 @@ class TemplateFinder ...@@ -35,9 +37,9 @@ class TemplateFinder
def execute def execute
if params[:name] if params[:name]
vendored_templates.find(params[:name]) vendored_templates.find(params[:name], project)
else else
vendored_templates.all vendored_templates.all(project)
end end
end end
end end
......
---
title: Add API support for issue and merge request templates
merge_request: 37890
author: Jan Beckmann
type: added
...@@ -13,15 +13,15 @@ This API is a project-specific version of these endpoints: ...@@ -13,15 +13,15 @@ This API is a project-specific version of these endpoints:
- [Gitignore templates](templates/gitignores.md) - [Gitignore templates](templates/gitignores.md)
- [GitLab CI/CD Configuration templates](templates/gitlab_ci_ymls.md) - [GitLab CI/CD Configuration templates](templates/gitlab_ci_ymls.md)
- [Open source license templates](templates/licenses.md) - [Open source license templates](templates/licenses.md)
- [Issue and merge request templates](../user/project/description_templates.md)
([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37890) in GitLab 13.3 as a
community contribution)
It deprecates these endpoints, which will be removed for API version 5. It deprecates these endpoints, which will be removed for API version 5.
In addition to templates common to the entire instance, project-specific In addition to templates common to the entire instance, project-specific
templates are also available from this API endpoint. templates are also available from this API endpoint.
Support will be added for [Issue and Merge Request templates](../user/project/description_templates.md)
in a future release.
Support for [Group-level file templates](../user/group/index.md#group-file-templates-premium) Support for [Group-level file templates](../user/group/index.md#group-file-templates-premium)
**(PREMIUM)** was [added](https://gitlab.com/gitlab-org/gitlab/-/issues/5987) **(PREMIUM)** was [added](https://gitlab.com/gitlab-org/gitlab/-/issues/5987)
in GitLab 11.5 in GitLab 11.5
...@@ -35,7 +35,7 @@ GET /projects/:id/templates/:type ...@@ -35,7 +35,7 @@ GET /projects/:id/templates/:type
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ---------- | ------ | -------- | ----------- | | ---------- | ------ | -------- | ----------- |
| `id` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) | | `id` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `type` | string | yes| The type `(dockerfiles|gitignores|gitlab_ci_ymls|licenses)` of the template | | `type` | string | yes| The type `(dockerfiles|gitignores|gitlab_ci_ymls|licenses|issues|merge_requests)` of the template |
Example response (licenses): Example response (licenses):
...@@ -101,7 +101,7 @@ GET /projects/:id/templates/:type/:key ...@@ -101,7 +101,7 @@ GET /projects/:id/templates/:type/:key
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ---------- | ------ | -------- | ----------- | | ---------- | ------ | -------- | ----------- |
| `id` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) | | `id` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `type` | string | yes| The type `(dockerfiles|gitignores|gitlab_ci_ymls|licenses)` of the template | | `type` | string | yes| The type `(dockerfiles|gitignores|gitlab_ci_ymls|licenses|issues|merge_requests)` of the template |
| `key` | string | yes | The key of the template, as obtained from the collection endpoint | | `key` | string | yes | The key of the template, as obtained from the collection endpoint |
| `project` | string | no | The project name to use when expanding placeholders in the template. Only affects licenses | | `project` | string | no | The project name to use when expanding placeholders in the template. Only affects licenses |
| `fullname` | string | no | The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses | | `fullname` | string | no | The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses |
......
...@@ -17,13 +17,15 @@ module EE ...@@ -17,13 +17,15 @@ module EE
def initialize(type, project, *args, &blk) def initialize(type, project, *args, &blk)
super super
finder = CUSTOM_TEMPLATES.fetch(type) if CUSTOM_TEMPLATES.key?(type)
@custom_templates = ::Gitlab::CustomFileTemplates.new(finder, project) finder = CUSTOM_TEMPLATES.fetch(type)
@custom_templates = ::Gitlab::CustomFileTemplates.new(finder, project)
end
end end
override :execute override :execute
def execute def execute
return super unless custom_templates.enabled? return super if custom_templates.nil? || !custom_templates.enabled?
if params[:name] if params[:name]
custom_templates.find(params[:name]) || super custom_templates.find(params[:name]) || super
......
...@@ -4,7 +4,7 @@ module API ...@@ -4,7 +4,7 @@ module API
class ProjectTemplates < Grape::API::Instance class ProjectTemplates < Grape::API::Instance
include PaginationParams include PaginationParams
TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses metrics_dashboard_ymls].freeze TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses metrics_dashboard_ymls issues merge_requests].freeze
# The regex is needed to ensure a period (e.g. agpl-3.0) # The regex is needed to ensure a period (e.g. agpl-3.0)
# isn't confused with a format type. We also need to allow encoded # isn't confused with a format type. We also need to allow encoded
# values (e.g. C%2B%2B for C++), so allow % and + as well. # values (e.g. C%2B%2B for C++), so allow % and + as well.
...@@ -14,7 +14,7 @@ module API ...@@ -14,7 +14,7 @@ module API
params do params do
requires :id, type: String, desc: 'The ID of a project' 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|metrics_dashboard_ymls) of the template' requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses|metrics_dashboard_ymls|issues|merge_requests) of the template'
end end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of templates available to this project' do desc 'Get a list of templates available to this project' do
...@@ -42,9 +42,13 @@ module API ...@@ -42,9 +42,13 @@ module API
end end
get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do
template = TemplateFinder begin
.build(params[:type], user_project, name: params[:name]) template = TemplateFinder
.execute .build(params[:type], user_project, name: params[:name])
.execute
rescue ::Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError
not_found!('Template')
end
not_found!('Template') unless template.present? not_found!('Template') unless template.present?
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe API::ProjectTemplates do RSpec.describe API::ProjectTemplates do
let_it_be(:public_project) { create(:project, :public, path: 'path.with.dot') } let_it_be(:public_project) { create(:project, :public, :repository, create_templates: :merge_request, path: 'path.with.dot') }
let_it_be(:private_project) { create(:project, :private) } let_it_be(:private_project) { create(:project, :private, :repository, create_templates: :issue) }
let_it_be(:developer) { create(:user) } let_it_be(:developer) { create(:user) }
let(:url_encoded_path) { "#{public_project.namespace.path}%2F#{public_project.path}" } let(:url_encoded_path) { "#{public_project.namespace.path}%2F#{public_project.path}" }
...@@ -71,6 +71,24 @@ RSpec.describe API::ProjectTemplates do ...@@ -71,6 +71,24 @@ RSpec.describe API::ProjectTemplates do
expect(json_response).to satisfy_one { |template| template['key'] == 'Default' } expect(json_response).to satisfy_one { |template| template['key'] == 'Default' }
end end
it 'returns issue templates' do
get api("/projects/#{private_project.id}/templates/issues", developer)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response.map {|t| t['key']}).to match_array(%w(bug feature_proposal template_test))
end
it 'returns merge request templates' do
get api("/projects/#{public_project.id}/templates/merge_requests")
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/template_list')
expect(json_response.map {|t| t['key']}).to match_array(%w(bug feature_proposal template_test))
end
it 'returns 400 for an unknown template type' do it 'returns 400 for an unknown template type' do
get api("/projects/#{public_project.id}/templates/unknown") get api("/projects/#{public_project.id}/templates/unknown")
...@@ -160,12 +178,42 @@ RSpec.describe API::ProjectTemplates do ...@@ -160,12 +178,42 @@ RSpec.describe API::ProjectTemplates do
expect(response).to match_response_schema('public_api/v4/license') expect(response).to match_response_schema('public_api/v4/license')
end end
it 'returns a specific issue template' do
get api("/projects/#{private_project.id}/templates/issues/bug", developer)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/template')
expect(json_response['name']).to eq('bug')
expect(json_response['content']).to eq('something valid')
end
it 'returns a specific merge request template' do
get api("/projects/#{public_project.id}/templates/merge_requests/feature_proposal")
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/template')
expect(json_response['name']).to eq('feature_proposal')
expect(json_response['content']).to eq('feature_proposal') # Content is identical to filename here
end
it 'returns 404 for an unknown specific template' do it 'returns 404 for an unknown specific template' do
get api("/projects/#{public_project.id}/templates/licenses/unknown") get api("/projects/#{public_project.id}/templates/licenses/unknown")
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:not_found)
end end
it 'returns 404 for an unknown issue template' do
get api("/projects/#{public_project.id}/templates/issues/unknown")
expect(response).to have_gitlab_http_status(:not_found)
end
it 'returns 404 for an unknown merge request template' do
get api("/projects/#{public_project.id}/templates/merge_requests/unknown")
expect(response).to have_gitlab_http_status(:not_found)
end
it 'denies access to an anonymous user on a private project' do it 'denies access to an anonymous user on a private project' do
get api("/projects/#{private_project.id}/templates/licenses/mit") get api("/projects/#{private_project.id}/templates/licenses/mit")
......
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