Commit ab22dae9 authored by Robert Speicher's avatar Robert Speicher

Merge branch 'ce-5306-more-custom-templates' into 'master'

CE backport of changes that introduce custom instance-level templates to EE

See merge request gitlab-org/gitlab-ce!21530
parents e7cb8a41 d65e31ab
class TemplateFinder
VENDORED_TEMPLATES = {
dockerfiles: ::Gitlab::Template::DockerfileTemplate,
gitignores: ::Gitlab::Template::GitignoreTemplate,
gitlab_ci_ymls: ::Gitlab::Template::GitlabCiYmlTemplate
}.freeze
class << self
def build(type, params = {})
if type == :licenses
LicenseTemplateFinder.new(params)
else
new(type, params)
end
end
end
attr_reader :type, :params
attr_reader :vendored_templates
private :vendored_templates
def initialize(type, params = {})
@type = type
@params = params
@vendored_templates = VENDORED_TEMPLATES.fetch(type)
end
def execute
if params[:name]
vendored_templates.find(params[:name])
else
vendored_templates.all
end
end
end
...@@ -158,32 +158,35 @@ module BlobHelper ...@@ -158,32 +158,35 @@ module BlobHelper
end end
def licenses_for_select def licenses_for_select
return @licenses_for_select if defined?(@licenses_for_select) @licenses_for_select ||= template_dropdown_names(TemplateFinder.build(:licenses).execute)
grouped_licenses = LicenseTemplateFinder.new.execute.group_by(&:category)
categories = grouped_licenses.keys
@licenses_for_select = categories.each_with_object({}) do |category, hash|
hash[category] = grouped_licenses[category].map do |license|
{ name: license.name, id: license.id }
end
end
end end
def ref_project def ref_project
@ref_project ||= @target_project || @project @ref_project ||= @target_project || @project
end end
def template_dropdown_names(items)
grouped = items.group_by(&:category)
categories = grouped.keys
categories.each_with_object({}) do |category, hash|
hash[category] = grouped[category].map do |item|
{ name: item.name, id: item.id }
end
end
end
private :template_dropdown_names
def gitignore_names def gitignore_names
@gitignore_names ||= Gitlab::Template::GitignoreTemplate.dropdown_names @gitignore_names ||= template_dropdown_names(TemplateFinder.build(:gitignores).execute)
end end
def gitlab_ci_ymls def gitlab_ci_ymls
@gitlab_ci_ymls ||= Gitlab::Template::GitlabCiYmlTemplate.dropdown_names(params[:context]) @gitlab_ci_ymls ||= template_dropdown_names(TemplateFinder.build(:gitlab_ci_ymls).execute)
end end
def dockerfile_names def dockerfile_names
@dockerfile_names ||= Gitlab::Template::DockerfileTemplate.dropdown_names @dockerfile_names ||= template_dropdown_names(TemplateFinder.build(:dockerfiles).execute)
end end
def blob_editor_paths def blob_editor_paths
......
...@@ -4,15 +4,12 @@ module API ...@@ -4,15 +4,12 @@ module API
GLOBAL_TEMPLATE_TYPES = { GLOBAL_TEMPLATE_TYPES = {
gitignores: { gitignores: {
klass: Gitlab::Template::GitignoreTemplate,
gitlab_version: 8.8 gitlab_version: 8.8
}, },
gitlab_ci_ymls: { gitlab_ci_ymls: {
klass: Gitlab::Template::GitlabCiYmlTemplate,
gitlab_version: 8.9 gitlab_version: 8.9
}, },
dockerfiles: { dockerfiles: {
klass: Gitlab::Template::DockerfileTemplate,
gitlab_version: 8.15 gitlab_version: 8.15
} }
}.freeze }.freeze
...@@ -36,7 +33,7 @@ module API ...@@ -36,7 +33,7 @@ module API
popular = declared(params)[:popular] popular = declared(params)[:popular]
popular = to_boolean(popular) if popular.present? popular = to_boolean(popular) if popular.present?
templates = LicenseTemplateFinder.new(popular: popular).execute templates = TemplateFinder.build(:licenses, popular: popular).execute
present paginate(::Kaminari.paginate_array(templates)), with: ::API::Entities::License present paginate(::Kaminari.paginate_array(templates)), with: ::API::Entities::License
end end
...@@ -49,7 +46,7 @@ module API ...@@ -49,7 +46,7 @@ module API
requires :name, type: String, desc: 'The name of the template' requires :name, type: String, desc: 'The name of the template'
end end
get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ } do get "templates/licenses/:name", requirements: { name: /[\w\.-]+/ } do
templates = LicenseTemplateFinder.new.execute templates = TemplateFinder.build(:licenses).execute
template = templates.find { |template| template.key == params[:name] } template = templates.find { |template| template.key == params[:name] }
not_found!('License') unless template.present? not_found!('License') unless template.present?
...@@ -63,7 +60,6 @@ module API ...@@ -63,7 +60,6 @@ module API
end end
GLOBAL_TEMPLATE_TYPES.each do |template_type, properties| GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
klass = properties[:klass]
gitlab_version = properties[:gitlab_version] gitlab_version = properties[:gitlab_version]
desc 'Get the list of the available template' do desc 'Get the list of the available template' do
...@@ -74,7 +70,7 @@ module API ...@@ -74,7 +70,7 @@ module API
use :pagination use :pagination
end end
get "templates/#{template_type}" do get "templates/#{template_type}" do
templates = ::Kaminari.paginate_array(klass.all) templates = ::Kaminari.paginate_array(TemplateFinder.new(template_type).execute)
present paginate(templates), with: Entities::TemplatesList present paginate(templates), with: Entities::TemplatesList
end end
...@@ -86,7 +82,8 @@ module API ...@@ -86,7 +82,8 @@ module API
requires :name, type: String, desc: 'The name of the template' requires :name, type: String, desc: 'The name of the template'
end end
get "templates/#{template_type}/:name" do get "templates/#{template_type}/:name" do
new_template = klass.find(declared(params)[:name]) finder = TemplateFinder.build(template_type, name: declared(params)[:name])
new_template = finder.execute
render_response(template_type, new_template) render_response(template_type, new_template)
end end
......
module Gitlab module Gitlab
module Template module Template
class BaseTemplate class BaseTemplate
def initialize(path, project = nil) attr_reader :category
def initialize(path, project = nil, category: nil)
@path = path @path = path
@category = category
@finder = self.class.finder(project) @finder = self.class.finder(project)
end end
def name def name
File.basename(@path, self.class.extension) File.basename(@path, self.class.extension)
end end
alias_method :id, :name
def content def content
@finder.read(@path) @finder.read(@path)
...@@ -62,7 +66,7 @@ module Gitlab ...@@ -62,7 +66,7 @@ module Gitlab
directory = category_directory(category) directory = category_directory(category)
files = finder(project).list_files_for(directory) files = finder(project).list_files_for(directory)
files.map { |f| new(f, project) }.sort files.map { |f| new(f, project, category: category) }.sort
end end
def category_directory(category) def category_directory(category)
......
...@@ -130,6 +130,33 @@ FactoryBot.define do ...@@ -130,6 +130,33 @@ FactoryBot.define do
end end
end end
# Build a custom repository by specifying a hash of `filename => content` in
# the transient `files` attribute. Each file will be created in its own
# commit, operating against the master branch. So, the following call:
#
# create(:project, :custom_repo, files: { 'foo/a.txt' => 'foo', 'b.txt' => bar' })
#
# will create a repository containing two files, and two commits, in master
trait :custom_repo do
transient do
files {}
end
after :create do |project, evaluator|
raise "Failed to create repository!" unless project.create_repository
evaluator.files.each do |filename, content|
project.repository.create_file(
project.creator,
filename,
content,
message: "Automatically created file #{filename}",
branch_name: 'master'
)
end
end
end
# Test repository - https://gitlab.com/gitlab-org/gitlab-test # Test repository - https://gitlab.com/gitlab-org/gitlab-test
trait :repository do trait :repository do
test_repo test_repo
......
require 'spec_helper'
describe TemplateFinder do
using RSpec::Parameterized::TableSyntax
describe '#build' do
where(:type, :expected_class) do
:dockerfiles | described_class
:gitignores | described_class
:gitlab_ci_ymls | described_class
:licenses | ::LicenseTemplateFinder
end
with_them do
subject { described_class.build(type) }
it { is_expected.to be_a(expected_class) }
end
end
describe '#execute' do
where(:type, :vendored_name) do
:dockerfiles | 'Binary'
:gitignores | 'Actionscript'
:gitlab_ci_ymls | 'Android'
end
with_them do
it 'returns all vendored templates when no name is specified' do
result = described_class.new(type).execute
expect(result).to include(have_attributes(name: vendored_name))
end
it 'returns only the specified vendored template when a name is specified' do
result = described_class.new(type, name: vendored_name).execute
expect(result).to have_attributes(name: vendored_name)
end
it 'returns nil when an unknown name is specified' do
result = described_class.new(type, name: 'unknown').execute
expect(result).to be_nil
end
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