60 lines
1.8 KiB
Ruby
60 lines
1.8 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
module Gitlab
|
||
|
module Changelog
|
||
|
# Parsing and generating of Markdown changelogs.
|
||
|
class Generator
|
||
|
# The regex used to parse a release header.
|
||
|
RELEASE_REGEX =
|
||
|
/^##\s+(?<version>#{Gitlab::Regex.unbounded_semver_regex})/.freeze
|
||
|
|
||
|
# The `input` argument must be a `String` containing the existing
|
||
|
# changelog Markdown. If no changelog exists, this should be an empty
|
||
|
# `String`.
|
||
|
def initialize(input = '')
|
||
|
@lines = input.lines
|
||
|
@locations = {}
|
||
|
|
||
|
@lines.each_with_index do |line, index|
|
||
|
matches = line.match(RELEASE_REGEX)
|
||
|
|
||
|
next if !matches || !matches[:version]
|
||
|
|
||
|
@locations[matches[:version]] = index
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# Generates the Markdown for the given release and returns the new
|
||
|
# changelog Markdown content.
|
||
|
#
|
||
|
# The `release` argument must be an instance of
|
||
|
# `Gitlab::Changelog::Release`.
|
||
|
def add(release)
|
||
|
versions = [release.version, *@locations.keys]
|
||
|
|
||
|
VersionSorter.rsort!(versions)
|
||
|
|
||
|
new_index = versions.index(release.version)
|
||
|
new_lines = @lines.dup
|
||
|
markdown = release.to_markdown
|
||
|
|
||
|
if (insert_after = versions[new_index + 1])
|
||
|
line_index = @locations[insert_after]
|
||
|
|
||
|
new_lines.insert(line_index, markdown)
|
||
|
else
|
||
|
# When adding to the end of the changelog, the previous section only
|
||
|
# has a single newline, resulting in the release section title
|
||
|
# following it immediately. When this is the case, we insert an extra
|
||
|
# empty line to keep the changelog readable in its raw form.
|
||
|
new_lines.push("\n") if versions.length > 1
|
||
|
new_lines.push(markdown.rstrip)
|
||
|
new_lines.push("\n")
|
||
|
end
|
||
|
|
||
|
new_lines.join
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|