diff --git a/lib/github_changelog_generator/generator/generator.rb b/lib/github_changelog_generator/generator/generator.rb index b349f63..ee30e42 100644 --- a/lib/github_changelog_generator/generator/generator.rb +++ b/lib/github_changelog_generator/generator/generator.rb @@ -95,12 +95,13 @@ module GitHubChangelogGenerator # @param [Array] pull_requests # @return [String] generated log for issues def issues_to_log(issues, pull_requests) - log = "" - bugs_a, enhancement_a, issues_a = parse_by_sections(issues, pull_requests) + sections = parse_by_sections(issues, pull_requests) - log += generate_sub_section(enhancement_a, options[:enhancement_prefix]) - log += generate_sub_section(bugs_a, options[:bug_prefix]) - log += generate_sub_section(issues_a, options[:issue_prefix]) + log = "" + log += generate_sub_section(sections[:breaking], options[:breaking_prefix]) + log += generate_sub_section(sections[:enhancement], options[:enhancement_prefix]) + log += generate_sub_section(sections[:bugs], options[:bug_prefix]) + log += generate_sub_section(sections[:issues], options[:issue_prefix]) log end @@ -109,47 +110,69 @@ module GitHubChangelogGenerator # # @param [Array] issues # @param [Array] pull_requests - # @return [Array] tuple of filtered arrays: (Bugs, Enhancements Issues) + # @return [Hash] Mapping of filtered arrays: (Bugs, Enhancements, Breaking stuff, Issues) def parse_by_sections(issues, pull_requests) - issues_a = [] - enhancement_a = [] - bugs_a = [] + sections = { + issues: [], + enhancements: [], + bugs: [], + breaking: [] + } issues.each do |dict| added = false + dict["labels"].each do |label| if options[:bug_labels].include?(label["name"]) - bugs_a.push(dict) + sections[:bugs] << dict added = true - next - end - if options[:enhancement_labels].include?(label["name"]) - enhancement_a.push(dict) + elsif options[:enhancement_labels].include?(label["name"]) + sections[:enhancements] << dict + added = true + elsif options[:breaking_labels].include?(label["name"]) + sections[:breaking] << dict added = true - next end + + break if added end - issues_a.push(dict) unless added + + sections[:issues] << dict unless added end + sort_pull_requests(pull_requests, sections) + end + + # This method iterates through PRs and sorts them into sections + # + # @param [Array] pull_requests + # @param [Hash] sections + # @return [Hash] sections + def sort_pull_requests(pull_requests, sections) added_pull_requests = [] pull_requests.each do |pr| + added = false + pr["labels"].each do |label| if options[:bug_labels].include?(label["name"]) - bugs_a.push(pr) - added_pull_requests.push(pr) - next - end - if options[:enhancement_labels].include?(label["name"]) - enhancement_a.push(pr) - added_pull_requests.push(pr) - next + sections[:bugs] << pr + added_pull_requests << pr + added = true + elsif options[:enhancement_labels].include?(label["name"]) + sections[:enhancements] << pr + added_pull_requests << pr + added = true + elsif options[:breaking_labels].include?(label["name"]) + sections[:breaking] << pr + added_pull_requests << pr + added = true end + + break if added end end added_pull_requests.each { |p| pull_requests.delete(p) } - - [bugs_a, enhancement_a, issues_a] + sections end end end diff --git a/lib/github_changelog_generator/options.rb b/lib/github_changelog_generator/options.rb index 4938793..f2b5c04 100644 --- a/lib/github_changelog_generator/options.rb +++ b/lib/github_changelog_generator/options.rb @@ -20,6 +20,8 @@ module GitHubChangelogGenerator due_tag enhancement_labels enhancement_prefix + breaking_labels + breaking_prefix exclude_labels exclude_tags exclude_tags_regex diff --git a/lib/github_changelog_generator/parser.rb b/lib/github_changelog_generator/parser.rb index 0b363bb..80165d8 100755 --- a/lib/github_changelog_generator/parser.rb +++ b/lib/github_changelog_generator/parser.rb @@ -70,6 +70,9 @@ module GitHubChangelogGenerator opts.on("--enhancement-label [LABEL]", "Setup custom label for enhancements section. Default is \"**Implemented enhancements:**\"") do |v| options[:enhancement_prefix] = v end + opts.on("--breaking-label [LABEL]", "Setup custom label for the breaking changes section. Default is \"**Breaking changes:**\"") do |v| + options[:breaking_prefix] = v + end opts.on("--issues-label [LABEL]", "Setup custom label for closed-issues section. Default is \"**Closed issues:**\"") do |v| options[:issue_prefix] = v end @@ -127,6 +130,9 @@ module GitHubChangelogGenerator opts.on("--enhancement-labels x,y,z", Array, 'Issues with the specified labels will be always added to "Implemented enhancements" section. Default is \'enhancement,Enhancement\'') do |list| options[:enhancement_labels] = list end + opts.on("--breaking-labels x,y,z", Array, 'Issues with these labels will be added to a new section, called "Breaking Changes". Default is \'backwards-incompatible\'') do |list| + options[:breaking_labels] = list + end opts.on("--issue-line-labels x,y,z", Array, 'The specified labels will be shown in brackets next to each matching issue. Use "ALL" to show all labels. Default is [].') do |list| options[:issue_line_labels] = list end @@ -208,6 +214,7 @@ module GitHubChangelogGenerator enhancement_labels: ["enhancement", "Enhancement", "Type: Enhancement"], bug_labels: ["bug", "Bug", "Type: Bug"], exclude_labels: ["duplicate", "question", "invalid", "wontfix", "Duplicate", "Question", "Invalid", "Wontfix", "Meta: Exclude From Changelog"], + breaking_labels: %w[backwards-incompatible breaking], issue_line_labels: [], max_issues: nil, simple_list: false, @@ -218,6 +225,7 @@ module GitHubChangelogGenerator issue_prefix: "**Closed issues:**", bug_prefix: "**Fixed bugs:**", enhancement_prefix: "**Implemented enhancements:**", + breaking_prefix: "**Breaking changes:**", http_cache: true ) end diff --git a/lib/github_changelog_generator/parser_file.rb b/lib/github_changelog_generator/parser_file.rb index e2a80d7..182ece6 100644 --- a/lib/github_changelog_generator/parser_file.rb +++ b/lib/github_changelog_generator/parser_file.rb @@ -67,7 +67,7 @@ module GitHubChangelogGenerator end KNOWN_ARRAY_KEYS = %i[exclude_labels include_labels bug_labels - enhancement_labels issue_line_labels between_tags exclude_tags] + enhancement_labels breaking_labels issue_line_labels between_tags exclude_tags] KNOWN_INTEGER_KEYS = [:max_issues] def convert_value(value, option_name) @@ -91,6 +91,7 @@ module GitHubChangelogGenerator header_label: :header, front_matter: :frontmatter, pr_label: :merge_prefix, + breaking_label: :breaking_prefix, issues_wo_labels: :add_issues_wo_labels, pr_wo_labels: :add_pr_wo_labels, pull_requests: :pulls, diff --git a/spec/unit/generator/generator_generation_spec.rb b/spec/unit/generator/generator_generation_spec.rb index c849eda..5a1b089 100644 --- a/spec/unit/generator/generator_generation_spec.rb +++ b/spec/unit/generator/generator_generation_spec.rb @@ -13,5 +13,61 @@ module GitHubChangelogGenerator end.not_to raise_error end end + + describe "#parse_by_sections" do + def label(name) + { "name" => name } + end + + def issue(title, labels) + { "title" => "issue #{title}", "labels" => labels.map { |l| label(l) } } + end + + def pr(title, labels) + { "title" => "pr #{title}", "labels" => labels.map { |l| label(l) } } + end + + def get_titles(issues) + issues.map { |issue| issue["title"] } + end + + let(:options) do + { + bug_labels: ["bug"], + enhancement_labels: ["enhancement"], + breaking_labels: ["breaking"] + } + end + + let(:issues) do + [ + issue("no labels", []), + issue("enhancement", ["enhancement"]), + issue("bug", ["bug"]), + issue("breaking", ["breaking"]), + issue("all the labels", %w[enhancement bug breaking]) + ] + end + + let(:pull_requests) do + [ + pr("no labels", []), + pr("enhancement", ["enhancement"]), + pr("bug", ["bug"]), + pr("breaking", ["breaking"]), + pr("all the labels", %w[enhancement bug breaking]) + ] + end + + it "works" do + sections = described_class.new(options).parse_by_sections(issues, pull_requests) + + expect(get_titles(sections[:issues])).to eq(["issue no labels"]) + expect(get_titles(sections[:enhancements])).to eq(["issue enhancement", "issue all the labels", "pr enhancement", "pr all the labels"]) + expect(get_titles(sections[:bugs])).to eq(["issue bug", "pr bug"]) + expect(get_titles(sections[:breaking])).to eq(["issue breaking", "pr breaking"]) + expect(get_titles(pull_requests)).to eq(["pr no labels"]) + end + end end end