147 lines
4.6 KiB
Ruby
147 lines
4.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module Template
|
|
class BaseTemplate
|
|
attr_accessor :category
|
|
|
|
def initialize(path, project = nil, category: nil)
|
|
@path = path
|
|
@category = category
|
|
@project = project
|
|
@finder = self.class.finder(project)
|
|
end
|
|
|
|
def name
|
|
File.basename(@path, self.class.extension)
|
|
end
|
|
alias_method :key, :name
|
|
|
|
def full_name
|
|
Pathname.new(@path)
|
|
.relative_path_from(self.class.base_dir)
|
|
.to_s
|
|
end
|
|
|
|
def content
|
|
blob = @finder.read(@path)
|
|
[description, blob].compact.join("\n")
|
|
end
|
|
|
|
def description
|
|
# override with a comment to be placed at the top of the blob.
|
|
end
|
|
|
|
def project_id
|
|
@project&.id
|
|
end
|
|
|
|
# Present for compatibility with license templates, which can replace text
|
|
# like `[fullname]` with a user-specified string. This is a no-op for
|
|
# other templates
|
|
def resolve!(_placeholders = {})
|
|
self
|
|
end
|
|
|
|
def to_json(*)
|
|
{ key: key, name: name, content: content }
|
|
end
|
|
|
|
alias_method :as_json, :to_json
|
|
|
|
def <=>(other)
|
|
name <=> other.name
|
|
end
|
|
|
|
class << self
|
|
def all(project = nil)
|
|
if categories.any?
|
|
categories.keys.flat_map { |cat| by_category(cat, project) }
|
|
else
|
|
by_category("", project)
|
|
end
|
|
end
|
|
|
|
def find(key, project = nil)
|
|
path = self.finder(project).find(key)
|
|
path.present? ? new(path, project) : nil
|
|
end
|
|
|
|
# Set categories as sub directories
|
|
# Example: { "category_name_1" => "directory_path_1", "category_name_2" => "directory_name_2" }
|
|
# Default is no category with all files in base dir of each class
|
|
def categories
|
|
{}
|
|
end
|
|
|
|
def extension
|
|
raise NotImplementedError
|
|
end
|
|
|
|
def base_dir
|
|
raise NotImplementedError
|
|
end
|
|
|
|
# Defines which strategy will be used to get templates files
|
|
# RepoTemplateFinder - Finds templates on project repository, templates are filtered per project
|
|
# GlobalTemplateFinder - Finds templates on gitlab installation source, templates can be used in all projects
|
|
def finder(project = nil)
|
|
raise NotImplementedError
|
|
end
|
|
|
|
def by_category(category, project = nil, empty_category_title: nil)
|
|
directory = category_directory(category)
|
|
files = finder(project).list_files_for(directory)
|
|
|
|
files.map { |f| new(f, project, category: category.presence || empty_category_title) }.sort
|
|
end
|
|
|
|
def category_directory(category)
|
|
return base_dir unless category.present?
|
|
|
|
File.join(base_dir, categories[category])
|
|
end
|
|
|
|
# `repository_template_names` - reads through Gitaly the actual templates names within a
|
|
# given project's repository. This is only used by issue and merge request templates,
|
|
# that need to call this once and then cache the returned value.
|
|
#
|
|
# `template_names` - is an alias to `repository_template_names`. It would read through
|
|
# Gitaly the actual template names within a given project's repository for all file templates
|
|
# other than `issue` and `merge request` description templates, which would instead
|
|
# overwrite the `template_names` method to return a redis cached version, by reading cached values
|
|
# from `repository.issue_template_names_hash` and `repository.merge_request_template_names_hash`
|
|
# methods.
|
|
def repository_template_names(project)
|
|
template_names_by_category(self.all(project))
|
|
end
|
|
alias_method :template_names, :repository_template_names
|
|
|
|
def template_names_by_category(items)
|
|
grouped = items.group_by(&:category)
|
|
categories = grouped.keys
|
|
|
|
categories.index_with do |category|
|
|
grouped[category].map do |item|
|
|
{ name: item.name, id: item.key, key: item.key, project_id: item.try(:project_id) }
|
|
end
|
|
end
|
|
end
|
|
|
|
def template_subsets(project = nil)
|
|
return [] if project && !project.repository.exists?
|
|
|
|
if categories.any?
|
|
categories.keys.to_h do |category|
|
|
files = self.by_category(category, project)
|
|
[category, files.map { |t| { key: t.key, name: t.name, content: t.content } }]
|
|
end
|
|
else
|
|
files = self.all(project)
|
|
files.map { |t| { key: t.key, name: t.name, content: t.content } }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|