github-changelog-generator/lib/github_changelog_generator/generator/section.rb
Eric Putnam 587557e1ac
Refactor generation code and allow custom sections
There's a lot in this PR.
- Added a Section class to more easily make the other changes and
  hopefully add flexibility for the future
- Added an option called `configure_sections` that allows you create
  your own custom sections. It blows away all other sections and uses
only the ones you give it.
- Added an option called `add_sections` that allows you to add_sections
  to the default section set
- Added an option called `include_merged` that can be used when
  configure_sections is defined. Configure sections blows away any and
all default sections so to get this one back, you have to set this
option.
- Added tests for this stuff

@HAIL9000 was a co-author. Because of a little git snafu, I accidentally
squashed all of our work into one so it looks like it was just me.

---

Refactor details:

Before this change, the code in generator.rb and generator_generation.rb was conflated and
method call flow went back and forth between the two files seemingly
randomly. They also both defined the exact same class, which is
un-ruby-ish. I tried to separate methods used for the whole changelog
generation from methods used for specific parts of the changelog and
move them into specific classes.

I reasoned that a changelog is a series of "entries" of all tagged
releases plus an extra entry for the unreleased entry. Each entry is
comprised of a header and a series of "sections" for that entry. Each
section is comprized of a list of issues and/or pull requests for that
entry. So the log contains entries, entries contain sections, and
sections contain issues & prs. I have structured the classes around this idea.

- lib/github_changelog_generator/generator/generator.rb is for code
related to generating the entire changelog.
- lib/github_changelog_generator/generator/entry.rb is for code related
to generating entries.
- lib/github_changelog_generator/generator/section.rb is for code
relating to geneating entry sections.

Issues and PRs are already special objects, so it doesn't make sense to
break those out into their own class.
2017-12-14 16:13:41 -08:00

84 lines
2.5 KiB
Ruby

module GitHubChangelogGenerator
# This class generates the content for a single section of a changelog entry.
# It turns the tagged issues and PRs into a well-formatted list of changes to
# be later incorporated into a changelog entry.
#
# @see GitHubChangelogGenerator::Entry
class Section
attr_accessor :name, :prefix, :issues, :labels
def initialize(opts = {})
@name = opts[:name]
@prefix = opts[:prefix]
@labels = opts[:labels] || []
@issues = opts[:issues] || []
@options = opts[:options] || Options.new({})
end
# @param [Array] issues List of issues on sub-section
# @param [String] prefix Name of sub-section
# @return [String] Generate section content
def generate_content
content = ""
if @issues.any?
content += "#{@prefix}\n\n" unless @options[:simple_list]
@issues.each do |issue|
merge_string = get_string_for_issue(issue)
content += "- #{merge_string}\n"
end
content += "\n"
end
content
end
private
# Parse issue and generate single line formatted issue line.
#
# Example output:
# - Add coveralls integration [\#223](https://github.com/skywinder/github-changelog-generator/pull/223) (@skywinder)
#
# @param [Hash] issue Fetched issue from GitHub
# @return [String] Markdown-formatted single issue
def get_string_for_issue(issue)
encapsulated_title = encapsulate_string issue["title"]
title_with_number = "#{encapsulated_title} [\\##{issue['number']}](#{issue['html_url']})"
if @options[:issue_line_labels].present?
title_with_number = "#{title_with_number}#{line_labels_for(issue)}"
end
issue_line_with_user(title_with_number, issue)
end
def issue_line_with_user(line, issue)
return line if !@options[:author] || issue["pull_request"].nil?
user = issue["user"]
return "#{line} ({Null user})" unless user
if @options[:usernames_as_github_logins]
"#{line} (@#{user['login']})"
else
"#{line} ([#{user['login']}](#{user['html_url']}))"
end
end
ENCAPSULATED_CHARACTERS = %w(< > * _ \( \) [ ] #)
# Encapsulate characters to make Markdown look as expected.
#
# @param [String] string
# @return [String] encapsulated input string
def encapsulate_string(string)
string = string.gsub('\\', '\\\\')
ENCAPSULATED_CHARACTERS.each do |char|
string = string.gsub(char, "\\#{char}")
end
string
end
end
end