diff --git a/lib/github_changelog_generator/argv_parser.rb b/lib/github_changelog_generator/argv_parser.rb index 74b1f93f..c8349e97 100755 --- a/lib/github_changelog_generator/argv_parser.rb +++ b/lib/github_changelog_generator/argv_parser.rb @@ -205,6 +205,9 @@ def parser opts.on("--[no-]verbose", "Run verbosely. Default is true.") do |v| options[:verbose] = v end + opts.on("--tag-order ORDER", "Tag ordering method. Two methods available: 'date' and 'semver'. Default is 'date'.") do |tag_order| + options[:tag_order] = tag_order + end opts.on("-v", "--version", "Print version number.") do |_v| puts "Version: #{GitHubChangelogGenerator::VERSION}" exit diff --git a/lib/github_changelog_generator/generator/generator_tags.rb b/lib/github_changelog_generator/generator/generator_tags.rb index e1fcba78..7ab7e4c8 100644 --- a/lib/github_changelog_generator/generator/generator_tags.rb +++ b/lib/github_changelog_generator/generator/generator_tags.rb @@ -9,7 +9,14 @@ def fetch_and_filter_tags all_tags = @fetcher.fetch_all_tags fetch_tags_dates(all_tags) # Creates a Hash @tag_times_hash - all_sorted_tags = sort_tags_by_date(all_tags) + all_sorted_tags = [] + if options[:tag_order] == "date" + all_sorted_tags = sort_tags_by_date(all_tags) + elsif options[:tag_order] == "semver" + all_sorted_tags = sort_tags_by_semantic_version(all_tags) + else + raise ChangelogGeneratorError, "unknown tag ordering method" + end @sorted_tags = filter_included_tags(all_sorted_tags) @sorted_tags = filter_excluded_tags(@sorted_tags) @@ -47,12 +54,25 @@ def build_tag_section_mapping(section_tags, filtered_tags) # Sort all tags by date, newest to oldest def sort_tags_by_date(tags) - puts "Sorting tags..." if options[:verbose] + puts "Sorting tags by date..." if options[:verbose] tags.sort_by! do |x| get_time_of_tag(x) end.reverse! end + # Sort all tags by semantic version + def sort_tags_by_semantic_version(tags) + puts "Sorting tags by semantic version..." if options[:verbose] + tags.sort_by! do |x| + name_of_tag = x.fetch("name") + parts = name_of_tag.split("-") + main_parts = parts[0].split(".") + pre_release_parts = parts[1] ? parts[1].split(".") : [] + build_metadata_parts = parts[2] ? parts[2].split(".") : [] + [main_parts.map(&:to_i), pre_release_parts, build_metadata_parts] + end.reverse! + end + # Returns date for given GitHub Tag hash # # Memoize the date by tag name. diff --git a/lib/github_changelog_generator/options.rb b/lib/github_changelog_generator/options.rb index d75ca771..7d664ad5 100644 --- a/lib/github_changelog_generator/options.rb +++ b/lib/github_changelog_generator/options.rb @@ -69,6 +69,7 @@ class Options < SimpleDelegator ssl_ca_file summary_labels summary_prefix + tag_order token unreleased unreleased_label diff --git a/lib/github_changelog_generator/parser.rb b/lib/github_changelog_generator/parser.rb index 443fcc01..7e28efc5 100755 --- a/lib/github_changelog_generator/parser.rb +++ b/lib/github_changelog_generator/parser.rb @@ -81,7 +81,8 @@ def default_options security_prefix: "**Security fixes:**", http_cache: true, require: [], - config_file: ".github_changelog_generator" + config_file: ".github_changelog_generator", + tag_order: "date" ) end end diff --git a/lib/github_changelog_generator/task.rb b/lib/github_changelog_generator/task.rb index fcfc5736..8cbd22dc 100644 --- a/lib/github_changelog_generator/task.rb +++ b/lib/github_changelog_generator/task.rb @@ -19,7 +19,7 @@ class RakeTask < ::Rake::TaskLib between_tags exclude_tags exclude_tags_regex since_tag max_issues github_site github_endpoint simple_list future_release release_branch verbose release_url - base configure_sections add_sections http_cache] + base configure_sections add_sections http_cache tag_order] OPTIONS.each do |o| attr_accessor o.to_sym diff --git a/spec/unit/generator/generator_tags_spec.rb b/spec/unit/generator/generator_tags_spec.rb index 83f1bffe..16fc3758 100644 --- a/spec/unit/generator/generator_tags_spec.rb +++ b/spec/unit/generator/generator_tags_spec.rb @@ -321,17 +321,46 @@ def tags_from_strings(tags_strings) subject do @generator.sort_tags_by_date(tags) end - context "sort unsorted tags" do + context "sort unsorted date tags" do let(:tags) { tags_from_strings %w[valid_tag1 valid_tag2 valid_tag3] } it { is_expected.to be_a_kind_of(Array) } it { is_expected.to match_array(tags.reverse!) } end - context "sort sorted tags" do + context "sort sorted date tags" do let(:tags) { tags_from_strings %w[valid_tag3 valid_tag2 valid_tag1] } it { is_expected.to be_a_kind_of(Array) } it { is_expected.to match_array(tags) } end end + + describe "#sort_tags_by_semantic_version" do + before(:all) do + @generator = GitHubChangelogGenerator::Generator.new + end + + subject do + @generator.sort_tags_by_semantic_version(tags) + end + context "sort unsorted semver tags" do + let(:tags) { tags_from_strings ["2.0.0", "1.2.4", "1.2.3+build.1", "1.2.3-beta.1", "2.1.0"] } + let(:sorted_tags) { tags_from_strings ["2.1.0", "2.0.0", "1.2.4", "1.2.3+build.1", "1.2.3-beta.1"] } + it { is_expected.to be_a_kind_of(Array) } + it { is_expected.to match_array(sorted_tags) } + end + context "sort sorted semver tags" do + let(:tags) { tags_from_strings ["2.1.0", "2.0.0", "1.2.4", "1.2.3+build.1", "1.2.3-beta.1"] } + + it { is_expected.to be_a_kind_of(Array) } + it { is_expected.to match_array(tags) } + end + + context "sort non-semver tags" do + let(:tags) { tags_from_strings %w[some_tag1 some_tag2] } + + it { is_expected.to be_a_kind_of(Array) } + it { is_expected.to match_array(tags) } + end + end end