gitlab-org--gitlab-foss/lib/gitlab/changelog/config.rb

118 lines
3.7 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Changelog
# Configuration settings used when generating changelogs.
class Config
# When rendering changelog entries, authors are not included.
AUTHORS_NONE = 'none'
# The default path to the configuration file as stored in the project's Git
# repository.
DEFAULT_FILE_PATH = '.gitlab/changelog_config.yml'
# The default date format to use for formatting release dates.
DEFAULT_DATE_FORMAT = '%Y-%m-%d'
# The default template to use for generating release sections.
DEFAULT_TEMPLATE = File.read(File.join(__dir__, 'template.tpl'))
# The regex to use for extracting the version from a Git tag.
#
# This regex is based on the official semantic versioning regex (as found
# on https://semver.org/), with the addition of allowing a "v" at the
# start of a tag name.
#
# We default to a strict regex as we simply don't know what kind of data
# users put in their tags. As such, using simpler patterns (e.g. just
# `\d+` for the major version) could lead to unexpected results.
#
# We use a String here as `Gitlab::UntrustedRegexp` is a mutable object.
DEFAULT_TAG_REGEX = '^v?(?P<major>0|[1-9]\d*)' \
'\.(?P<minor>0|[1-9]\d*)' \
'\.(?P<patch>0|[1-9]\d*)' \
'(?:-(?P<pre>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))' \
'?(?:\+(?P<meta>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
attr_accessor :date_format, :categories, :template, :tag_regex, :always_credit_user_ids
def self.from_git(project, user = nil, path = nil)
yaml = project.repository.changelog_config('HEAD', path.presence || DEFAULT_FILE_PATH)
if yaml.present?
from_hash(project, YAML.safe_load(yaml), user)
else
new(project)
end
end
def self.from_hash(project, hash, user = nil)
config = new(project)
if (date = hash['date_format'])
config.date_format = date
end
if (template = hash['template'])
config.template =
begin
TemplateParser::Parser.new.parse_and_transform(template)
rescue TemplateParser::Error => e
raise Error, e.message
end
end
if (categories = hash['categories'])
if categories.is_a?(Hash)
config.categories = categories
else
raise Error, 'The "categories" configuration key must be a Hash'
end
end
if (regex = hash['tag_regex'])
config.tag_regex = regex
end
config.always_credit_user_ids = Set.new
if (group_paths = Array(hash['include_groups']))
group_paths.each do |group_path|
group = Group.find_by_full_path(group_path)
config.always_credit_user_ids.merge(group&.users_ids_of_direct_members&.compact) if user&.can?(:read_group, group)
end
end
config
end
def initialize(project)
@project = project
@date_format = DEFAULT_DATE_FORMAT
@template =
begin
TemplateParser::Parser.new.parse_and_transform(DEFAULT_TEMPLATE)
rescue TemplateParser::Error => e
raise Error, e.message
end
@categories = {}
@tag_regex = DEFAULT_TAG_REGEX
end
def contributor?(user)
@project.team.contributor?(user&.id)
end
def always_credit_author?(user)
always_credit_user_ids&.include?(user&.id) || false
end
def category(name)
@categories[name] || name
end
def format_date(date)
date.strftime(@date_format)
end
end
end
end