github-changelog-generator/lib/github_changelog_generator/options.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

137 lines
3.2 KiB
Ruby

# frozen_string_literal: true
require "delegate"
require "github_changelog_generator/helper"
module GitHubChangelogGenerator
# This class wraps Options, and knows a list of known options. Others options
# will raise exceptions.
class Options < SimpleDelegator
# Raised on intializing with unknown keys in the values hash,
# and when trying to store a value on an unknown key.
UnsupportedOptionError = Class.new(ArgumentError)
# List of valid option names
KNOWN_OPTIONS = %i[
add_issues_wo_labels
add_pr_wo_labels
add_sections
author
base
between_tags
bug_labels
bug_prefix
cache_file
cache_log
compare_link
date_format
due_tag
enhancement_labels
enhancement_prefix
breaking_labels
breaking_prefix
configure_sections
exclude_labels
exclude_tags
exclude_tags_regex
filter_issues_by_milestone
frontmatter
future_release
github_endpoint
github_site
header
http_cache
include_labels
issue_prefix
issue_line_labels
issues
max_issues
merge_prefix
output
project
pulls
release_branch
release_url
require
simple_list
since_tag
ssl_ca_file
token
unreleased
unreleased_label
unreleased_only
user
usernames_as_github_logins
verbose
]
# @param values [Hash]
#
# @raise [UnsupportedOptionError] if given values contain unknown options
def initialize(values)
super(values)
unsupported_options.any? && raise(UnsupportedOptionError, unsupported_options.inspect)
end
# Set option key to val.
#
# @param key [Symbol]
# @param val [Object]
#
# @raise [UnsupportedOptionError] when trying to set an unknown option
def []=(key, val)
supported_option?(key) || raise(UnsupportedOptionError, key.inspect)
values[key] = val
end
# @return [Hash]
def to_hash
values
end
# Loads the configured Ruby files from the --require option.
def load_custom_ruby_files
self[:require].each { |f| require f }
end
# Pretty-prints a censored options hash, if :verbose.
def print_options
return unless self[:verbose]
Helper.log.info "Using these options:"
pp(censored_values)
puts ""
end
# Boolean method for whether the user is using configure_sections
def configure_sections?
!self[:configure_sections].nil? && !self[:configure_sections].empty?
end
# Boolean method for whether the user is using add_sections
def add_sections?
!self[:add_sections].nil? && !self[:add_sections].empty?
end
private
def values
__getobj__
end
# Returns a censored options hash.
#
# @return [Hash] The GitHub `:token` key is censored in the output.
def censored_values
values.clone.tap { |opts| opts[:token] = opts[:token].nil? ? "No token used" : "hidden value" }
end
def unsupported_options
values.keys - KNOWN_OPTIONS
end
def supported_option?(key)
KNOWN_OPTIONS.include?(key)
end
end
end