github_changelog_generator 1.15.0.pre.alpha → 1.15.0.pre.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +20 -10
- data/Rakefile +2 -3
- data/lib/github_changelog_generator/generator/generator.rb +49 -26
- data/lib/github_changelog_generator/generator/generator_tags.rb +1 -1
- data/lib/github_changelog_generator/octo_fetcher.rb +58 -64
- data/lib/github_changelog_generator/options.rb +2 -1
- data/lib/github_changelog_generator/parser.rb +8 -108
- data/lib/github_changelog_generator/parser_file.rb +2 -1
- data/lib/github_changelog_generator/task.rb +1 -3
- data/lib/github_changelog_generator/version.rb +1 -1
- data/spec/unit/generator/generator_generation_spec.rb +56 -0
- data/spec/unit/generator/generator_tags_spec.rb +5 -0
- data/spec/unit/options_spec.rb +4 -4
- data/spec/unit/parser_spec.rb +0 -79
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 55def2416dfef54779832b68f186965d4c62bbd0
         | 
| 4 | 
            +
              data.tar.gz: c9f978a6b01aab0356b676e7749f1b25d4aacc93
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: acdbbbae3679145b85639750184fffd39efe3d94ea2447f3429341655bd9ea94860f1a1eea65f970437ae2894aeffc145685ef34cda687acf90123d45dc7b6b0
         | 
| 7 | 
            +
              data.tar.gz: 7cf8cf180df005695f5d3882299ce4ad4ef3b504dd0bfbba9806efe925fc1ebc666224b00eacbeda63add590ccd3b74ad19b40032c4fb70df07778cca444c29a
         | 
    
        data/LICENSE
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            The MIT License (MIT)
         | 
| 2 | 
            -
            Copyright (c) 2016 Petr Korolev
         | 
| 2 | 
            +
            Copyright (c) 2016-2017 Petr Korolev
         | 
| 3 3 |  | 
| 4 4 | 
             
            Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
         | 
| 5 5 |  | 
    
        data/README.md
    CHANGED
    
    | @@ -30,9 +30,14 @@ GitHub Changelog Generator  | |
| 30 30 | 
             
            Since you don't have to fill your `CHANGELOG.md` manually now: just run the script, relax and take a cup of :coffee: before your next release! :tada:
         | 
| 31 31 |  | 
| 32 32 | 
             
            ### *What’s the point of a change log?*
         | 
| 33 | 
            +
             | 
| 33 34 | 
             
            To make it easier for users and contributors to see precisely what notable changes have been made between each release (or version) of the project.
         | 
| 35 | 
            +
             | 
| 34 36 | 
             
            ### *Why should I care?*
         | 
| 35 | 
            -
             | 
| 37 | 
            +
             | 
| 38 | 
            +
            Because software tools are for _people_. "Changelogs make it easier for users and
         | 
| 39 | 
            +
            contributors to see precisely what notable changes have been made between each
         | 
| 40 | 
            +
            release (or version) of the project."
         | 
| 36 41 |  | 
| 37 42 | 
             
            :arrow_right: *[http://keepachangelog.com](http://keepachangelog.com)*
         | 
| 38 43 |  | 
| @@ -71,32 +76,31 @@ See also Troubleshooting. | |
| 71 76 |  | 
| 72 77 |  | 
| 73 78 | 
             
            ## Usage
         | 
| 74 | 
            -
            **It's really simple!**
         | 
| 75 79 |  | 
| 76 | 
            -
            -  | 
| 80 | 
            +
            -  Run this:
         | 
| 77 81 |  | 
| 78 | 
            -
                  github_changelog_generator
         | 
| 79 | 
            -
             | 
| 80 | 
            -
            -  Or, run this from anywhere:
         | 
| 81 82 | 
             
                  `github_changelog_generator -u github_username -p github_project`
         | 
| 82 83 | 
             
                  `github_changelog_generator  github_username/github_project`
         | 
| 83 84 |  | 
| 84 | 
            -
            -  | 
| 85 | 
            +
            - For Github Enterprise repos, specify *both* `--github-site` and `--github-api` options:
         | 
| 85 86 |  | 
| 86 87 | 
             
                  github_changelog_generator --github-site="https://github.yoursite.com" \
         | 
| 87 88 | 
             
                                             --github-api="https://github.yoursite.com/api/v3/"
         | 
| 88 89 |  | 
| 89 | 
            -
            This generates a  | 
| 90 | 
            +
            This generates a `CHANGELOG.md`, with pretty Markdown formatting.
         | 
| 90 91 |  | 
| 91 92 | 
             
            ### Params
         | 
| 93 | 
            +
             | 
| 92 94 | 
             
            Type `github_changelog_generator --help` for details.
         | 
| 93 95 |  | 
| 94 96 | 
             
            For more details about params, read the Wiki page: [**Advanced change log generation examples**](https://github.com/skywinder/github-changelog-generator/wiki/Advanced-change-log-generation-examples)
         | 
| 95 97 |  | 
| 96 98 | 
             
            ### Params File
         | 
| 99 | 
            +
             | 
| 97 100 | 
             
            In your project root, you can put a params file named `.github_changelog_generator` to override default params:
         | 
| 98 101 |  | 
| 99 102 | 
             
            Example:
         | 
| 103 | 
            +
             | 
| 100 104 | 
             
            ```
         | 
| 101 105 | 
             
            unreleased=false
         | 
| 102 106 | 
             
            future-release=5.0.0
         | 
| @@ -106,6 +110,7 @@ since-tag=1.0.0 | |
| 106 110 | 
             
            ### GitHub token
         | 
| 107 111 |  | 
| 108 112 | 
             
            GitHub only allows 50 unauthenticated requests per hour.
         | 
| 113 | 
            +
             | 
| 109 114 | 
             
            Therefore, it's recommended to run this script with authentication by using a **token**.
         | 
| 110 115 |  | 
| 111 116 | 
             
            Here's how:
         | 
| @@ -143,7 +148,7 @@ If you have a `HISTORY.md` file in your project, it will automatically be picked | |
| 143 148 | 
             
            You love `rake`? We do, too! So, we've made it even easier for you:
         | 
| 144 149 | 
             
            we've provided a `rake` task library for your changelog generation.
         | 
| 145 150 |  | 
| 146 | 
            -
             | 
| 151 | 
            +
            Configure the task in your `Rakefile`:
         | 
| 147 152 |  | 
| 148 153 | 
             
            ```ruby
         | 
| 149 154 | 
             
            require 'github_changelog_generator/task'
         | 
| @@ -154,11 +159,14 @@ GitHubChangelogGenerator::RakeTask.new :changelog do |config| | |
| 154 159 | 
             
            end
         | 
| 155 160 | 
             
            ```
         | 
| 156 161 |  | 
| 157 | 
            -
            All command | 
| 162 | 
            +
            All command-line options can be passed to the `rake` task as `config`
         | 
| 163 | 
            +
            parameters. And since you're naming the `rake` task yourself, you can create
         | 
| 164 | 
            +
            as many as you want.
         | 
| 158 165 |  | 
| 159 166 | 
             
            You can look for params names from the [parser source code (#setup_parser)](https://github.com/skywinder/github-changelog-generator/blob/master/lib/github_changelog_generator/parser.rb). For example, to translate the bugs label to Portuguese, instead of setting `config.bugs_label`, you have to set `config.bug_prefix`, and so on.
         | 
| 160 167 |  | 
| 161 168 | 
             
            ## Features and advantages of this project
         | 
| 169 | 
            +
             | 
| 162 170 | 
             
            - Generate canonical, neat change log file, followed by [basic change log guidelines](http://keepachangelog.com) :gem:
         | 
| 163 171 | 
             
            - Optionally generate **Unreleased** changes (closed issues that have not released yet) :dizzy:
         | 
| 164 172 | 
             
            - **GitHub Enterprise support** via command line options! :factory:
         | 
| @@ -179,12 +187,14 @@ You can look for params names from the [parser source code (#setup_parser)](http | |
| 179 187 |  | 
| 180 188 |  | 
| 181 189 | 
             
            ### Alternatives
         | 
| 190 | 
            +
             | 
| 182 191 | 
             
            Here is a [wikipage list of alternatives](https://github.com/skywinder/Github-Changelog-Generator/wiki/Alternatives) that I found. But none satisfied my requirements.
         | 
| 183 192 |  | 
| 184 193 | 
             
            *If you know other projects, feel free to edit this Wiki page!*
         | 
| 185 194 |  | 
| 186 195 |  | 
| 187 196 | 
             
            ### Projects using this library
         | 
| 197 | 
            +
             | 
| 188 198 | 
             
            Here's a [wikipage list of projects](https://github.com/skywinder/Github-Changelog-Generator/wiki/Projects-using-Github-Changelog-Generator).
         | 
| 189 199 |  | 
| 190 200 | 
             
            If you've used this project in a live app, please let me know! Nothing makes me happier than seeing someone else take my work and go wild with it.
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -9,12 +9,11 @@ require "fileutils" | |
| 9 9 | 
             
            require "overcommit"
         | 
| 10 10 |  | 
| 11 11 | 
             
            RuboCop::RakeTask.new
         | 
| 12 | 
            -
            RSpec::Core::RakeTask.new | 
| 12 | 
            +
            RSpec::Core::RakeTask.new
         | 
| 13 13 |  | 
| 14 14 | 
             
            desc "When releasing the gem, re-fetch latest cacert.pem from curl.haxx.se. Developer task."
         | 
| 15 15 | 
             
            task :update_ssl_ca_file do
         | 
| 16 16 | 
             
              `pushd lib/github_changelog_generator/ssl_certs && curl --remote-name --time-cond cacert.pem https://curl.haxx.se/ca/cacert.pem && popd`
         | 
| 17 17 | 
             
            end
         | 
| 18 18 |  | 
| 19 | 
            -
            task  | 
| 20 | 
            -
            task default: %i[rubocop rspec]
         | 
| 19 | 
            +
            task default: %i[rubocop spec]
         | 
| @@ -95,12 +95,13 @@ module GitHubChangelogGenerator | |
| 95 95 | 
             
                # @param [Array] pull_requests
         | 
| 96 96 | 
             
                # @return [String] generated log for issues
         | 
| 97 97 | 
             
                def issues_to_log(issues, pull_requests)
         | 
| 98 | 
            -
                   | 
| 99 | 
            -
                  bugs_a, enhancement_a, issues_a = parse_by_sections(issues, pull_requests)
         | 
| 98 | 
            +
                  sections = parse_by_sections(issues, pull_requests)
         | 
| 100 99 |  | 
| 101 | 
            -
                  log  | 
| 102 | 
            -
                  log += generate_sub_section( | 
| 103 | 
            -
                  log += generate_sub_section( | 
| 100 | 
            +
                  log = ""
         | 
| 101 | 
            +
                  log += generate_sub_section(sections[:breaking], options[:breaking_prefix])
         | 
| 102 | 
            +
                  log += generate_sub_section(sections[:enhancements], options[:enhancement_prefix])
         | 
| 103 | 
            +
                  log += generate_sub_section(sections[:bugs], options[:bug_prefix])
         | 
| 104 | 
            +
                  log += generate_sub_section(sections[:issues], options[:issue_prefix])
         | 
| 104 105 | 
             
                  log
         | 
| 105 106 | 
             
                end
         | 
| 106 107 |  | 
| @@ -109,47 +110,69 @@ module GitHubChangelogGenerator | |
| 109 110 | 
             
                #
         | 
| 110 111 | 
             
                # @param [Array] issues
         | 
| 111 112 | 
             
                # @param [Array] pull_requests
         | 
| 112 | 
            -
                # @return [ | 
| 113 | 
            +
                # @return [Hash] Mapping of filtered arrays: (Bugs, Enhancements, Breaking stuff, Issues)
         | 
| 113 114 | 
             
                def parse_by_sections(issues, pull_requests)
         | 
| 114 | 
            -
                   | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 115 | 
            +
                  sections = {
         | 
| 116 | 
            +
                    issues: [],
         | 
| 117 | 
            +
                    enhancements: [],
         | 
| 118 | 
            +
                    bugs: [],
         | 
| 119 | 
            +
                    breaking: []
         | 
| 120 | 
            +
                  }
         | 
| 117 121 |  | 
| 118 122 | 
             
                  issues.each do |dict|
         | 
| 119 123 | 
             
                    added = false
         | 
| 124 | 
            +
             | 
| 120 125 | 
             
                    dict["labels"].each do |label|
         | 
| 121 126 | 
             
                      if options[:bug_labels].include?(label["name"])
         | 
| 122 | 
            -
                         | 
| 127 | 
            +
                        sections[:bugs] << dict
         | 
| 123 128 | 
             
                        added = true
         | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 129 | 
            +
                      elsif options[:enhancement_labels].include?(label["name"])
         | 
| 130 | 
            +
                        sections[:enhancements] << dict
         | 
| 131 | 
            +
                        added = true
         | 
| 132 | 
            +
                      elsif options[:breaking_labels].include?(label["name"])
         | 
| 133 | 
            +
                        sections[:breaking] << dict
         | 
| 128 134 | 
             
                        added = true
         | 
| 129 | 
            -
                        next
         | 
| 130 135 | 
             
                      end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                      break if added
         | 
| 131 138 | 
             
                    end
         | 
| 132 | 
            -
             | 
| 139 | 
            +
             | 
| 140 | 
            +
                    sections[:issues] << dict unless added
         | 
| 133 141 | 
             
                  end
         | 
| 134 142 |  | 
| 143 | 
            +
                  sort_pull_requests(pull_requests, sections)
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                # This method iterates through PRs and sorts them into sections
         | 
| 147 | 
            +
                #
         | 
| 148 | 
            +
                # @param [Array] pull_requests
         | 
| 149 | 
            +
                # @param [Hash] sections
         | 
| 150 | 
            +
                # @return [Hash] sections
         | 
| 151 | 
            +
                def sort_pull_requests(pull_requests, sections)
         | 
| 135 152 | 
             
                  added_pull_requests = []
         | 
| 136 153 | 
             
                  pull_requests.each do |pr|
         | 
| 154 | 
            +
                    added = false
         | 
| 155 | 
            +
             | 
| 137 156 | 
             
                    pr["labels"].each do |label|
         | 
| 138 157 | 
             
                      if options[:bug_labels].include?(label["name"])
         | 
| 139 | 
            -
                         | 
| 140 | 
            -
                        added_pull_requests | 
| 141 | 
            -
                         | 
| 142 | 
            -
                       | 
| 143 | 
            -
             | 
| 144 | 
            -
                         | 
| 145 | 
            -
                         | 
| 146 | 
            -
             | 
| 158 | 
            +
                        sections[:bugs] << pr
         | 
| 159 | 
            +
                        added_pull_requests << pr
         | 
| 160 | 
            +
                        added = true
         | 
| 161 | 
            +
                      elsif options[:enhancement_labels].include?(label["name"])
         | 
| 162 | 
            +
                        sections[:enhancements] << pr
         | 
| 163 | 
            +
                        added_pull_requests << pr
         | 
| 164 | 
            +
                        added = true
         | 
| 165 | 
            +
                      elsif options[:breaking_labels].include?(label["name"])
         | 
| 166 | 
            +
                        sections[:breaking] << pr
         | 
| 167 | 
            +
                        added_pull_requests << pr
         | 
| 168 | 
            +
                        added = true
         | 
| 147 169 | 
             
                      end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                      break if added
         | 
| 148 172 | 
             
                    end
         | 
| 149 173 | 
             
                  end
         | 
| 150 174 | 
             
                  added_pull_requests.each { |p| pull_requests.delete(p) }
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                  [bugs_a, enhancement_a, issues_a]
         | 
| 175 | 
            +
                  sections
         | 
| 153 176 | 
             
                end
         | 
| 154 177 | 
             
              end
         | 
| 155 178 | 
             
            end
         | 
| @@ -31,21 +31,27 @@ module GitHubChangelogGenerator | |
| 31 31 | 
             
                  @project      = @options[:project]
         | 
| 32 32 | 
             
                  @since        = @options[:since]
         | 
| 33 33 | 
             
                  @http_cache   = @options[:http_cache]
         | 
| 34 | 
            -
                   | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
                    init_cache
         | 
| 38 | 
            -
                  end
         | 
| 39 | 
            -
                  @github_token = fetch_github_token
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                  @request_options               = { per_page: PER_PAGE_NUMBER }
         | 
| 42 | 
            -
                  @github_options                = {}
         | 
| 43 | 
            -
                  @github_options[:access_token] = @github_token unless @github_token.nil?
         | 
| 44 | 
            -
                  @github_options[:api_endpoint] = @options[:github_endpoint] unless @options[:github_endpoint].nil?
         | 
| 45 | 
            -
             | 
| 34 | 
            +
                  @cache_file   = nil
         | 
| 35 | 
            +
                  @cache_log    = nil
         | 
| 36 | 
            +
                  prepare_cache
         | 
| 46 37 | 
             
                  configure_octokit_ssl
         | 
| 38 | 
            +
                  @client = Octokit::Client.new(github_options)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def prepare_cache
         | 
| 42 | 
            +
                  return unless @http_cache
         | 
| 43 | 
            +
                  @cache_file = @options.fetch(:cache_file) { File.join(Dir.tmpdir, "github-changelog-http-cache") }
         | 
| 44 | 
            +
                  @cache_log  = @options.fetch(:cache_log) { File.join(Dir.tmpdir, "github-changelog-logger.log") }
         | 
| 45 | 
            +
                  init_cache
         | 
| 46 | 
            +
                end
         | 
| 47 47 |  | 
| 48 | 
            -
             | 
| 48 | 
            +
                def github_options
         | 
| 49 | 
            +
                  result = {}
         | 
| 50 | 
            +
                  github_token = fetch_github_token
         | 
| 51 | 
            +
                  result[:access_token] = github_token if github_token
         | 
| 52 | 
            +
                  endpoint = @options[:github_endpoint]
         | 
| 53 | 
            +
                  result[:api_endpoint] = endpoint if endpoint
         | 
| 54 | 
            +
                  result
         | 
| 49 55 | 
             
                end
         | 
| 50 56 |  | 
| 51 57 | 
             
                def configure_octokit_ssl
         | 
| @@ -54,21 +60,19 @@ module GitHubChangelogGenerator | |
| 54 60 | 
             
                end
         | 
| 55 61 |  | 
| 56 62 | 
             
                def init_cache
         | 
| 57 | 
            -
                   | 
| 58 | 
            -
                    serializer: Marshal,
         | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
                  }
         | 
| 63 | 
            -
                  stack = Faraday::RackBuilder.new do |builder|
         | 
| 64 | 
            -
                    builder.use Faraday::HttpCache, middleware_opts
         | 
| 63 | 
            +
                  Octokit.middleware = Faraday::RackBuilder.new do |builder|
         | 
| 64 | 
            +
                    builder.use(Faraday::HttpCache, serializer: Marshal,
         | 
| 65 | 
            +
                                                    store: ActiveSupport::Cache::FileStore.new(@cache_file),
         | 
| 66 | 
            +
                                                    logger: Logger.new(@cache_log),
         | 
| 67 | 
            +
                                                    shared_cache: false)
         | 
| 65 68 | 
             
                    builder.use Octokit::Response::RaiseError
         | 
| 66 69 | 
             
                    builder.adapter Faraday.default_adapter
         | 
| 67 70 | 
             
                    # builder.response :logger
         | 
| 68 71 | 
             
                  end
         | 
| 69 | 
            -
                  Octokit.middleware = stack
         | 
| 70 72 | 
             
                end
         | 
| 71 73 |  | 
| 74 | 
            +
                DEFAULT_REQUEST_OPTIONS = { per_page: PER_PAGE_NUMBER }
         | 
| 75 | 
            +
             | 
| 72 76 | 
             
                # Fetch all tags from repo
         | 
| 73 77 | 
             
                #
         | 
| 74 78 | 
             
                # @return [Array <Hash>] array of tags
         | 
| @@ -84,7 +88,7 @@ module GitHubChangelogGenerator | |
| 84 88 | 
             
                def calculate_pages(client, method, request_options)
         | 
| 85 89 | 
             
                  # Makes the first API call so that we can call last_response
         | 
| 86 90 | 
             
                  check_github_response do
         | 
| 87 | 
            -
                    client.send(method, user_project,  | 
| 91 | 
            +
                    client.send(method, user_project, DEFAULT_REQUEST_OPTIONS.merge(request_options))
         | 
| 88 92 | 
             
                  end
         | 
| 89 93 |  | 
| 90 94 | 
             
                  last_response = client.last_response
         | 
| @@ -104,7 +108,7 @@ module GitHubChangelogGenerator | |
| 104 108 | 
             
                  page_i      = 0
         | 
| 105 109 | 
             
                  count_pages = calculate_pages(@client, "tags", {})
         | 
| 106 110 |  | 
| 107 | 
            -
                  iterate_pages(@client, "tags" | 
| 111 | 
            +
                  iterate_pages(@client, "tags") do |new_tags|
         | 
| 108 112 | 
             
                    page_i += PER_PAGE_NUMBER
         | 
| 109 113 | 
             
                    print_in_same_line("Fetching tags... #{page_i}/#{count_pages * PER_PAGE_NUMBER}")
         | 
| 110 114 | 
             
                    tags.concat(new_tags)
         | 
| @@ -118,8 +122,13 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 118 122 | 
             
                    Helper.log.info "Found #{tags.count} tags"
         | 
| 119 123 | 
             
                  end
         | 
| 120 124 | 
             
                  # tags are a Sawyer::Resource. Convert to hash
         | 
| 121 | 
            -
                  tags | 
| 122 | 
            -
             | 
| 125 | 
            +
                  tags.map { |resource| stringify_keys_deep(resource.to_hash) }
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                def closed_pr_options
         | 
| 129 | 
            +
                  @closed_pr_options ||= {
         | 
| 130 | 
            +
                    filter: "all", labels: nil, state: "closed"
         | 
| 131 | 
            +
                  }.tap { |options| options[:since] = @since if @since }
         | 
| 123 132 | 
             
                end
         | 
| 124 133 |  | 
| 125 134 | 
             
                # This method fetch all closed issues and separate them to pull requests and pure issues
         | 
| @@ -129,17 +138,10 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 129 138 | 
             
                def fetch_closed_issues_and_pr
         | 
| 130 139 | 
             
                  print "Fetching closed issues...\r" if @options[:verbose]
         | 
| 131 140 | 
             
                  issues = []
         | 
| 132 | 
            -
                  options = {
         | 
| 133 | 
            -
                    state: "closed",
         | 
| 134 | 
            -
                    filter: "all",
         | 
| 135 | 
            -
                    labels: nil
         | 
| 136 | 
            -
                  }
         | 
| 137 | 
            -
                  options[:since] = @since unless @since.nil?
         | 
| 138 | 
            -
             | 
| 139 141 | 
             
                  page_i      = 0
         | 
| 140 | 
            -
                  count_pages = calculate_pages(@client, "issues",  | 
| 142 | 
            +
                  count_pages = calculate_pages(@client, "issues", closed_pr_options)
         | 
| 141 143 |  | 
| 142 | 
            -
                  iterate_pages(@client, "issues",  | 
| 144 | 
            +
                  iterate_pages(@client, "issues", closed_pr_options) do |new_issues|
         | 
| 143 145 | 
             
                    page_i += PER_PAGE_NUMBER
         | 
| 144 146 | 
             
                    print_in_same_line("Fetching issues... #{page_i}/#{count_pages * PER_PAGE_NUMBER}")
         | 
| 145 147 | 
             
                    issues.concat(new_issues)
         | 
| @@ -148,12 +150,9 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 148 150 | 
             
                  print_empty_line
         | 
| 149 151 | 
             
                  Helper.log.info "Received issues: #{issues.count}"
         | 
| 150 152 |  | 
| 151 | 
            -
                  issues = issues.map { |h| stringify_keys_deep(h.to_hash) }
         | 
| 152 | 
            -
             | 
| 153 153 | 
             
                  # separate arrays of issues and pull requests:
         | 
| 154 | 
            -
                  issues. | 
| 155 | 
            -
             | 
| 156 | 
            -
                  end
         | 
| 154 | 
            +
                  issues.map { |issue| stringify_keys_deep(issue.to_hash) }
         | 
| 155 | 
            +
                        .partition { |issue_or_pr| issue_or_pr["pull_request"].nil? }
         | 
| 157 156 | 
             
                end
         | 
| 158 157 |  | 
| 159 158 | 
             
                # Fetch all pull requests. We need them to detect :merged_at parameter
         | 
| @@ -179,8 +178,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 179 178 | 
             
                  print_empty_line
         | 
| 180 179 |  | 
| 181 180 | 
             
                  Helper.log.info "Pull Request count: #{pull_requests.count}"
         | 
| 182 | 
            -
                  pull_requests | 
| 183 | 
            -
                  pull_requests
         | 
| 181 | 
            +
                  pull_requests.map { |pull_request| stringify_keys_deep(pull_request.to_hash) }
         | 
| 184 182 | 
             
                end
         | 
| 185 183 |  | 
| 186 184 | 
             
                # Fetch event for all issues and add them to 'events'
         | 
| @@ -195,10 +193,10 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 195 193 | 
             
                    issues_slice.each do |issue|
         | 
| 196 194 | 
             
                      threads << Thread.new do
         | 
| 197 195 | 
             
                        issue["events"] = []
         | 
| 198 | 
            -
                        iterate_pages(@client, "issue_events", issue["number"] | 
| 196 | 
            +
                        iterate_pages(@client, "issue_events", issue["number"]) do |new_event|
         | 
| 199 197 | 
             
                          issue["events"].concat(new_event)
         | 
| 200 198 | 
             
                        end
         | 
| 201 | 
            -
                        issue["events"] = issue["events"].map { | | 
| 199 | 
            +
                        issue["events"] = issue["events"].map { |event| stringify_keys_deep(event.to_hash) }
         | 
| 202 200 | 
             
                        print_in_same_line("Fetching events for issues and PR: #{i + 1}/#{issues.count}")
         | 
| 203 201 | 
             
                        i += 1
         | 
| 204 202 | 
             
                      end
         | 
| @@ -256,14 +254,15 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 256 254 | 
             
                      stringify_keys_deep(value)
         | 
| 257 255 | 
             
                    end
         | 
| 258 256 | 
             
                  when Hash
         | 
| 259 | 
            -
                    indata.each_with_object({}) do |( | 
| 260 | 
            -
                      output[ | 
| 257 | 
            +
                    indata.each_with_object({}) do |(key, value), output|
         | 
| 258 | 
            +
                      output[key.to_s] = stringify_keys_deep(value)
         | 
| 261 259 | 
             
                    end
         | 
| 262 260 | 
             
                  else
         | 
| 263 261 | 
             
                    indata
         | 
| 264 262 | 
             
                  end
         | 
| 265 263 | 
             
                end
         | 
| 266 264 |  | 
| 265 | 
            +
                # Exception raised to warn about moved repositories.
         | 
| 267 266 | 
             
                MovedPermanentlyError = Class.new(RuntimeError)
         | 
| 268 267 |  | 
| 269 268 | 
             
                # Iterates through all pages until there are no more :next pages to follow
         | 
| @@ -274,29 +273,21 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 274 273 | 
             
                #
         | 
| 275 274 | 
             
                # @yield [Sawyer::Resource] An OctoKit-provided response (which can be empty)
         | 
| 276 275 | 
             
                #
         | 
| 277 | 
            -
                # @return [ | 
| 276 | 
            +
                # @return [void]
         | 
| 278 277 | 
             
                def iterate_pages(client, method, *args)
         | 
| 279 | 
            -
                   | 
| 280 | 
            -
                  args.push(@request_options.merge(request_opts))
         | 
| 281 | 
            -
             | 
| 282 | 
            -
                  number_of_pages = 1
         | 
| 278 | 
            +
                  args << DEFAULT_REQUEST_OPTIONS.merge(extract_request_args(args))
         | 
| 283 279 |  | 
| 284 280 | 
             
                  check_github_response { client.send(method, user_project, *args) }
         | 
| 285 | 
            -
                  last_response = client.last_response
         | 
| 286 | 
            -
             | 
| 287 | 
            -
                    raise MovedPermanentlyError, last_response.data[:url]
         | 
| 281 | 
            +
                  last_response = client.last_response.tap do |response|
         | 
| 282 | 
            +
                    raise(MovedPermanentlyError, response.data[:url]) if response.status == 301
         | 
| 288 283 | 
             
                  end
         | 
| 289 284 |  | 
| 290 285 | 
             
                  yield(last_response.data)
         | 
| 291 286 |  | 
| 292 287 | 
             
                  until (next_one = last_response.rels[:next]).nil?
         | 
| 293 | 
            -
                    number_of_pages += 1
         | 
| 294 | 
            -
             | 
| 295 288 | 
             
                    last_response = check_github_response { next_one.get }
         | 
| 296 289 | 
             
                    yield(last_response.data)
         | 
| 297 290 | 
             
                  end
         | 
| 298 | 
            -
             | 
| 299 | 
            -
                  number_of_pages
         | 
| 300 291 | 
             
                end
         | 
| 301 292 |  | 
| 302 293 | 
             
                def extract_request_args(args)
         | 
| @@ -317,14 +308,17 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 317 308 | 
             
                    yield
         | 
| 318 309 | 
             
                  end
         | 
| 319 310 | 
             
                rescue MovedPermanentlyError => e
         | 
| 320 | 
            -
                   | 
| 321 | 
            -
                  sys_abort("The repository has moved, please update your configuration")
         | 
| 311 | 
            +
                  fail_with_message(e, "The repository has moved, update your configuration")
         | 
| 322 312 | 
             
                rescue Octokit::Forbidden => e
         | 
| 323 | 
            -
                   | 
| 324 | 
            -
                  sys_abort("Exceeded retry limit")
         | 
| 313 | 
            +
                  fail_with_message(e, "Exceeded retry limit")
         | 
| 325 314 | 
             
                rescue Octokit::Unauthorized => e
         | 
| 315 | 
            +
                  fail_with_message(e, "Error: wrong GitHub token")
         | 
| 316 | 
            +
                end
         | 
| 317 | 
            +
             | 
| 318 | 
            +
                # Presents the exception, and the aborts with the message.
         | 
| 319 | 
            +
                def fail_with_message(e, message)
         | 
| 326 320 | 
             
                  Helper.log.error("#{e.class}: #{e.message}")
         | 
| 327 | 
            -
                  sys_abort( | 
| 321 | 
            +
                  sys_abort(message)
         | 
| 328 322 | 
             
                end
         | 
| 329 323 |  | 
| 330 324 | 
             
                # Exponential backoff
         | 
| @@ -373,7 +367,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'" | |
| 373 367 | 
             
                #
         | 
| 374 368 | 
             
                # @return [String]
         | 
| 375 369 | 
             
                def fetch_github_token
         | 
| 376 | 
            -
                  env_var = @options[:token]  | 
| 370 | 
            +
                  env_var = @options[:token].presence || ENV["CHANGELOG_GITHUB_TOKEN"]
         | 
| 377 371 |  | 
| 378 372 | 
             
                  Helper.log.warn NO_TOKEN_PROVIDED unless env_var
         | 
| 379 373 |  | 
| @@ -20,13 +20,14 @@ module GitHubChangelogGenerator | |
| 20 20 | 
             
                  due_tag
         | 
| 21 21 | 
             
                  enhancement_labels
         | 
| 22 22 | 
             
                  enhancement_prefix
         | 
| 23 | 
            +
                  breaking_labels
         | 
| 24 | 
            +
                  breaking_prefix
         | 
| 23 25 | 
             
                  exclude_labels
         | 
| 24 26 | 
             
                  exclude_tags
         | 
| 25 27 | 
             
                  exclude_tags_regex
         | 
| 26 28 | 
             
                  filter_issues_by_milestone
         | 
| 27 29 | 
             
                  frontmatter
         | 
| 28 30 | 
             
                  future_release
         | 
| 29 | 
            -
                  git_remote
         | 
| 30 31 | 
             
                  github_endpoint
         | 
| 31 32 | 
             
                  github_site
         | 
| 32 33 | 
             
                  header
         | 
| @@ -19,8 +19,6 @@ module GitHubChangelogGenerator | |
| 19 19 | 
             
                    abort [e, parser].join("\n")
         | 
| 20 20 | 
             
                  end
         | 
| 21 21 |  | 
| 22 | 
            -
                  fetch_user_and_project(options)
         | 
| 23 | 
            -
             | 
| 24 22 | 
             
                  abort(parser.banner) unless options[:user] && options[:project]
         | 
| 25 23 |  | 
| 26 24 | 
             
                  print_options(options)
         | 
| @@ -72,6 +70,9 @@ module GitHubChangelogGenerator | |
| 72 70 | 
             
                    opts.on("--enhancement-label [LABEL]", "Setup custom label for enhancements section. Default is \"**Implemented enhancements:**\"") do |v|
         | 
| 73 71 | 
             
                      options[:enhancement_prefix] = v
         | 
| 74 72 | 
             
                    end
         | 
| 73 | 
            +
                    opts.on("--breaking-label [LABEL]", "Setup custom label for the breaking changes section. Default is \"**Breaking changes:**\"") do |v|
         | 
| 74 | 
            +
                      options[:breaking_prefix] = v
         | 
| 75 | 
            +
                    end
         | 
| 75 76 | 
             
                    opts.on("--issues-label [LABEL]", "Setup custom label for closed-issues section. Default is \"**Closed issues:**\"") do |v|
         | 
| 76 77 | 
             
                      options[:issue_prefix] = v
         | 
| 77 78 | 
             
                    end
         | 
| @@ -129,6 +130,9 @@ module GitHubChangelogGenerator | |
| 129 130 | 
             
                    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|
         | 
| 130 131 | 
             
                      options[:enhancement_labels] = list
         | 
| 131 132 | 
             
                    end
         | 
| 133 | 
            +
                    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|
         | 
| 134 | 
            +
                      options[:breaking_labels] = list
         | 
| 135 | 
            +
                    end
         | 
| 132 136 | 
             
                    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|
         | 
| 133 137 | 
             
                      options[:issue_line_labels] = list
         | 
| 134 138 | 
             
                    end
         | 
| @@ -210,6 +214,7 @@ module GitHubChangelogGenerator | |
| 210 214 | 
             
                    enhancement_labels: ["enhancement", "Enhancement", "Type: Enhancement"],
         | 
| 211 215 | 
             
                    bug_labels: ["bug", "Bug", "Type: Bug"],
         | 
| 212 216 | 
             
                    exclude_labels: ["duplicate", "question", "invalid", "wontfix", "Duplicate", "Question", "Invalid", "Wontfix", "Meta: Exclude From Changelog"],
         | 
| 217 | 
            +
                    breaking_labels: %w[backwards-incompatible breaking],
         | 
| 213 218 | 
             
                    issue_line_labels: [],
         | 
| 214 219 | 
             
                    max_issues: nil,
         | 
| 215 220 | 
             
                    simple_list: false,
         | 
| @@ -220,114 +225,9 @@ module GitHubChangelogGenerator | |
| 220 225 | 
             
                    issue_prefix: "**Closed issues:**",
         | 
| 221 226 | 
             
                    bug_prefix: "**Fixed bugs:**",
         | 
| 222 227 | 
             
                    enhancement_prefix: "**Implemented enhancements:**",
         | 
| 223 | 
            -
                     | 
| 228 | 
            +
                    breaking_prefix: "**Breaking changes:**",
         | 
| 224 229 | 
             
                    http_cache: true
         | 
| 225 230 | 
             
                  )
         | 
| 226 231 | 
             
                end
         | 
| 227 | 
            -
             | 
| 228 | 
            -
                # If `:user` or `:project` not set in options, try setting them
         | 
| 229 | 
            -
                # Valid unnamed parameters:
         | 
| 230 | 
            -
                # 1) in 1 param: repo_name/project
         | 
| 231 | 
            -
                # 2) in 2 params: repo name project
         | 
| 232 | 
            -
                def self.fetch_user_and_project(options)
         | 
| 233 | 
            -
                  if options[:user].nil? || options[:project].nil?
         | 
| 234 | 
            -
                    user, project = user_and_project_from_git(options, ARGV[0], ARGV[1])
         | 
| 235 | 
            -
                    options[:user] ||= user
         | 
| 236 | 
            -
                    options[:project] ||= project
         | 
| 237 | 
            -
                  end
         | 
| 238 | 
            -
                end
         | 
| 239 | 
            -
             | 
| 240 | 
            -
                # Sets `:user` and `:project` in `options` from CLI arguments or `git remote`
         | 
| 241 | 
            -
                # @param [String] arg0 first argument in cli
         | 
| 242 | 
            -
                # @param [String] arg1 second argument in cli
         | 
| 243 | 
            -
                # @return [Array<String>] user and project, or nil if unsuccessful
         | 
| 244 | 
            -
                def self.user_and_project_from_git(options, arg0 = nil, arg1 = nil)
         | 
| 245 | 
            -
                  user, project = user_project_from_option(arg0, arg1, options[:github_site])
         | 
| 246 | 
            -
                  unless user && project
         | 
| 247 | 
            -
                    if ENV["RUBYLIB"] =~ /ruby-debug-ide/
         | 
| 248 | 
            -
                      user = "skywinder"
         | 
| 249 | 
            -
                      project = "changelog_test"
         | 
| 250 | 
            -
                    else
         | 
| 251 | 
            -
                      remote = `git config --get remote.#{options[:git_remote]}.url`
         | 
| 252 | 
            -
                      user, project = user_project_from_remote(remote)
         | 
| 253 | 
            -
                    end
         | 
| 254 | 
            -
                  end
         | 
| 255 | 
            -
             | 
| 256 | 
            -
                  [user, project]
         | 
| 257 | 
            -
                end
         | 
| 258 | 
            -
             | 
| 259 | 
            -
                # Returns GitHub username and project from CLI arguments
         | 
| 260 | 
            -
                #
         | 
| 261 | 
            -
                # @param arg0 [String] This parameter takes two forms: Either a full
         | 
| 262 | 
            -
                #                      GitHub URL, or a 'username/projectname', or
         | 
| 263 | 
            -
                #                      simply a GitHub username
         | 
| 264 | 
            -
                # @param arg1 [String] If arg0 is given as a username,
         | 
| 265 | 
            -
                #                      then arg1 can given as a projectname
         | 
| 266 | 
            -
                # @param github_site [String] Domain name of GitHub site
         | 
| 267 | 
            -
                #
         | 
| 268 | 
            -
                # @return [Array, nil] user and project, or nil if unsuccessful
         | 
| 269 | 
            -
                def self.user_project_from_option(arg0, arg1, github_site)
         | 
| 270 | 
            -
                  user = nil
         | 
| 271 | 
            -
                  project = nil
         | 
| 272 | 
            -
                  github_site ||= "github.com"
         | 
| 273 | 
            -
                  if arg0 && !arg1
         | 
| 274 | 
            -
                    # this match should parse  strings such "https://github.com/skywinder/Github-Changelog-Generator" or
         | 
| 275 | 
            -
                    # "skywinder/Github-Changelog-Generator" to user and name
         | 
| 276 | 
            -
                    match = /(?:.+#{Regexp.escape(github_site)}\/)?(.+)\/(.+)/.match(arg0)
         | 
| 277 | 
            -
             | 
| 278 | 
            -
                    begin
         | 
| 279 | 
            -
                      param = match[2].nil?
         | 
| 280 | 
            -
                    rescue StandardError
         | 
| 281 | 
            -
                      puts "Can't detect user and name from first parameter: '#{arg0}' -> exit'"
         | 
| 282 | 
            -
                      return
         | 
| 283 | 
            -
                    end
         | 
| 284 | 
            -
                    if param
         | 
| 285 | 
            -
                      return
         | 
| 286 | 
            -
                    else
         | 
| 287 | 
            -
                      user = match[1]
         | 
| 288 | 
            -
                      project = match[2]
         | 
| 289 | 
            -
                    end
         | 
| 290 | 
            -
                  end
         | 
| 291 | 
            -
                  [user, project]
         | 
| 292 | 
            -
                end
         | 
| 293 | 
            -
             | 
| 294 | 
            -
                # These patterns match these formats:
         | 
| 295 | 
            -
                #
         | 
| 296 | 
            -
                # ```
         | 
| 297 | 
            -
                # origin	git@github.com:skywinder/Github-Changelog-Generator.git (fetch)
         | 
| 298 | 
            -
                # git@github.com:skywinder/Github-Changelog-Generator.git
         | 
| 299 | 
            -
                # ```
         | 
| 300 | 
            -
                #
         | 
| 301 | 
            -
                # and
         | 
| 302 | 
            -
                #
         | 
| 303 | 
            -
                # ```
         | 
| 304 | 
            -
                # origin	https://github.com/skywinder/ChangelogMerger (fetch)
         | 
| 305 | 
            -
                # https://github.com/skywinder/ChangelogMerger
         | 
| 306 | 
            -
                # ```
         | 
| 307 | 
            -
                GIT_REMOTE_PATTERNS = [
         | 
| 308 | 
            -
                  /.*(?:[:\/])(?<user>(?:-|\w|\.)*)\/(?<project>(?:-|\w|\.)*)(?:\.git).*/,
         | 
| 309 | 
            -
                  /.*\/(?<user>(?:-|\w|\.)*)\/(?<project>(?:-|\w|\.)*).*/
         | 
| 310 | 
            -
                ]
         | 
| 311 | 
            -
             | 
| 312 | 
            -
                # Returns GitHub username and project from git remote output
         | 
| 313 | 
            -
                #
         | 
| 314 | 
            -
                # @param git_remote_output [String] Output of git remote command
         | 
| 315 | 
            -
                #
         | 
| 316 | 
            -
                # @return [Array] user and project
         | 
| 317 | 
            -
                def self.user_project_from_remote(git_remote_output)
         | 
| 318 | 
            -
                  user = nil
         | 
| 319 | 
            -
                  project = nil
         | 
| 320 | 
            -
                  GIT_REMOTE_PATTERNS.each do |git_remote_pattern|
         | 
| 321 | 
            -
                    git_remote_pattern =~ git_remote_output
         | 
| 322 | 
            -
             | 
| 323 | 
            -
                    if Regexp.last_match
         | 
| 324 | 
            -
                      user = Regexp.last_match(:user)
         | 
| 325 | 
            -
                      project = Regexp.last_match(:project)
         | 
| 326 | 
            -
                      break
         | 
| 327 | 
            -
                    end
         | 
| 328 | 
            -
                  end
         | 
| 329 | 
            -
             | 
| 330 | 
            -
                  [user, project]
         | 
| 331 | 
            -
                end
         | 
| 332 232 | 
             
              end
         | 
| 333 233 | 
             
            end
         | 
| @@ -67,7 +67,7 @@ module GitHubChangelogGenerator | |
| 67 67 | 
             
                end
         | 
| 68 68 |  | 
| 69 69 | 
             
                KNOWN_ARRAY_KEYS = %i[exclude_labels include_labels bug_labels
         | 
| 70 | 
            -
                                      enhancement_labels issue_line_labels between_tags exclude_tags]
         | 
| 70 | 
            +
                                      enhancement_labels breaking_labels issue_line_labels between_tags exclude_tags]
         | 
| 71 71 | 
             
                KNOWN_INTEGER_KEYS = [:max_issues]
         | 
| 72 72 |  | 
| 73 73 | 
             
                def convert_value(value, option_name)
         | 
| @@ -91,6 +91,7 @@ module GitHubChangelogGenerator | |
| 91 91 | 
             
                  header_label: :header,
         | 
| 92 92 | 
             
                  front_matter: :frontmatter,
         | 
| 93 93 | 
             
                  pr_label: :merge_prefix,
         | 
| 94 | 
            +
                  breaking_label: :breaking_prefix,
         | 
| 94 95 | 
             
                  issues_wo_labels: :add_issues_wo_labels,
         | 
| 95 96 | 
             
                  pr_wo_labels: :add_pr_wo_labels,
         | 
| 96 97 | 
             
                  pull_requests: :pulls,
         | 
| @@ -48,13 +48,11 @@ module GitHubChangelogGenerator | |
| 48 48 | 
             
                    # mimick parse_options
         | 
| 49 49 | 
             
                    options = Parser.default_options
         | 
| 50 50 |  | 
| 51 | 
            -
                    Parser.fetch_user_and_project(options)
         | 
| 52 | 
            -
             | 
| 53 51 | 
             
                    OPTIONS.each do |o|
         | 
| 54 52 | 
             
                      v = instance_variable_get("@#{o}")
         | 
| 55 53 | 
             
                      options[o.to_sym] = v unless v.nil?
         | 
| 56 54 | 
             
                    end
         | 
| 57 | 
            -
             | 
| 55 | 
            +
                    abort "user and project are required." unless options[:user] && options[:project]
         | 
| 58 56 | 
             
                    generator = Generator.new options
         | 
| 59 57 |  | 
| 60 58 | 
             
                    log = generator.compound_changelog
         | 
| @@ -13,5 +13,61 @@ module GitHubChangelogGenerator | |
| 13 13 | 
             
                    end.not_to raise_error
         | 
| 14 14 | 
             
                  end
         | 
| 15 15 | 
             
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                describe "#parse_by_sections" do
         | 
| 18 | 
            +
                  def label(name)
         | 
| 19 | 
            +
                    { "name" => name }
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def issue(title, labels)
         | 
| 23 | 
            +
                    { "title" => "issue #{title}", "labels" => labels.map { |l| label(l) } }
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def pr(title, labels)
         | 
| 27 | 
            +
                    { "title" => "pr #{title}", "labels" => labels.map { |l| label(l) } }
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def get_titles(issues)
         | 
| 31 | 
            +
                    issues.map { |issue| issue["title"] }
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  let(:options) do
         | 
| 35 | 
            +
                    {
         | 
| 36 | 
            +
                      bug_labels: ["bug"],
         | 
| 37 | 
            +
                      enhancement_labels: ["enhancement"],
         | 
| 38 | 
            +
                      breaking_labels: ["breaking"]
         | 
| 39 | 
            +
                    }
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  let(:issues) do
         | 
| 43 | 
            +
                    [
         | 
| 44 | 
            +
                      issue("no labels", []),
         | 
| 45 | 
            +
                      issue("enhancement", ["enhancement"]),
         | 
| 46 | 
            +
                      issue("bug", ["bug"]),
         | 
| 47 | 
            +
                      issue("breaking", ["breaking"]),
         | 
| 48 | 
            +
                      issue("all the labels", %w[enhancement bug breaking])
         | 
| 49 | 
            +
                    ]
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  let(:pull_requests) do
         | 
| 53 | 
            +
                    [
         | 
| 54 | 
            +
                      pr("no labels", []),
         | 
| 55 | 
            +
                      pr("enhancement", ["enhancement"]),
         | 
| 56 | 
            +
                      pr("bug", ["bug"]),
         | 
| 57 | 
            +
                      pr("breaking", ["breaking"]),
         | 
| 58 | 
            +
                      pr("all the labels", %w[enhancement bug breaking])
         | 
| 59 | 
            +
                    ]
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  it "works" do
         | 
| 63 | 
            +
                    sections = described_class.new(options).parse_by_sections(issues, pull_requests)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    expect(get_titles(sections[:issues])).to eq(["issue no labels"])
         | 
| 66 | 
            +
                    expect(get_titles(sections[:enhancements])).to eq(["issue enhancement", "issue all the labels", "pr enhancement", "pr all the labels"])
         | 
| 67 | 
            +
                    expect(get_titles(sections[:bugs])).to eq(["issue bug", "pr bug"])
         | 
| 68 | 
            +
                    expect(get_titles(sections[:breaking])).to eq(["issue breaking", "pr breaking"])
         | 
| 69 | 
            +
                    expect(get_titles(pull_requests)).to eq(["pr no labels"])
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
                end
         | 
| 16 72 | 
             
              end
         | 
| 17 73 | 
             
            end
         | 
| @@ -182,6 +182,11 @@ describe GitHubChangelogGenerator::Generator do | |
| 182 182 | 
             
                    let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "2") }
         | 
| 183 183 | 
             
                    it { is_expected.to be_a Array }
         | 
| 184 184 | 
             
                    it { is_expected.to match_array(tags_from_strings(%w[1 2])) }
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                    context "with since tag set to the most recent tag" do
         | 
| 187 | 
            +
                      let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "1") }
         | 
| 188 | 
            +
                      it { is_expected.to match_array(tags_from_strings(%w[1])) }
         | 
| 189 | 
            +
                    end
         | 
| 185 190 | 
             
                  end
         | 
| 186 191 |  | 
| 187 192 | 
             
                  context "with invalid since tag" do
         | 
    
        data/spec/unit/options_spec.rb
    CHANGED
    
    | @@ -12,7 +12,7 @@ RSpec.describe GitHubChangelogGenerator::Options do | |
| 12 12 | 
             
                  it "raises an error" do
         | 
| 13 13 | 
             
                    expect do
         | 
| 14 14 | 
             
                      described_class.new(
         | 
| 15 | 
            -
                         | 
| 15 | 
            +
                        project: "rails",
         | 
| 16 16 | 
             
                        strength: "super-strength",
         | 
| 17 17 | 
             
                        wisdom: "deep"
         | 
| 18 18 | 
             
                      )
         | 
| @@ -22,13 +22,13 @@ RSpec.describe GitHubChangelogGenerator::Options do | |
| 22 22 | 
             
              end
         | 
| 23 23 |  | 
| 24 24 | 
             
              describe "#[]=(key, value)" do
         | 
| 25 | 
            -
                let(:options) { described_class.new( | 
| 25 | 
            +
                let(:options) { described_class.new(project: "rails") }
         | 
| 26 26 |  | 
| 27 27 | 
             
                context "with known options" do
         | 
| 28 28 | 
             
                  it "sets the option value" do
         | 
| 29 29 | 
             
                    expect do
         | 
| 30 | 
            -
                      options[: | 
| 31 | 
            -
                    end.to change { options[: | 
| 30 | 
            +
                      options[:project] = "trails"
         | 
| 31 | 
            +
                    end.to change { options[:project] }.to "trails"
         | 
| 32 32 | 
             
                  end
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
    
        data/spec/unit/parser_spec.rb
    CHANGED
    
    | @@ -1,83 +1,4 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            describe GitHubChangelogGenerator::Parser do
         | 
| 4 | 
            -
              describe ".user_project_from_remote" do
         | 
| 5 | 
            -
                context "when remote is type 1" do
         | 
| 6 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_remote("origin  https://github.com/skywinder/ActionSheetPicker-3.0 (fetch)") }
         | 
| 7 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 8 | 
            -
                  it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) }
         | 
| 9 | 
            -
                end
         | 
| 10 | 
            -
                context "when remote is type 2" do
         | 
| 11 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_remote("https://github.com/skywinder/ActionSheetPicker-3.0") }
         | 
| 12 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 13 | 
            -
                  it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) }
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
                context "when remote is type 3" do
         | 
| 16 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_remote("https://github.com/skywinder/ActionSheetPicker-3.0") }
         | 
| 17 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 18 | 
            -
                  it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) }
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
                context "when remote is type 4" do
         | 
| 21 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_remote("origin git@github.com:skywinder/ActionSheetPicker-3.0.git (fetch)") }
         | 
| 22 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 23 | 
            -
                  it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) }
         | 
| 24 | 
            -
                end
         | 
| 25 | 
            -
                context "when remote is invalid" do
         | 
| 26 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_remote("some invalid text") }
         | 
| 27 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 28 | 
            -
                  it { is_expected.to match_array([nil, nil]) }
         | 
| 29 | 
            -
                end
         | 
| 30 | 
            -
              end
         | 
| 31 | 
            -
              describe ".user_project_from_option" do
         | 
| 32 | 
            -
                context "when option is invalid" do
         | 
| 33 | 
            -
                  it("should return nil") { expect(GitHubChangelogGenerator::Parser.user_project_from_option("blah", nil, nil)).to be_nil }
         | 
| 34 | 
            -
                end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                context "when option is valid" do
         | 
| 37 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", nil, nil) }
         | 
| 38 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 39 | 
            -
                  it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) }
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
                context "when option nil" do
         | 
| 42 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_option(nil, nil, nil) }
         | 
| 43 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 44 | 
            -
                  it { is_expected.to match_array([nil, nil]) }
         | 
| 45 | 
            -
                end
         | 
| 46 | 
            -
                context "when site is nil" do
         | 
| 47 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", nil, nil) }
         | 
| 48 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 49 | 
            -
                  it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) }
         | 
| 50 | 
            -
                end
         | 
| 51 | 
            -
                context "when site is valid" do
         | 
| 52 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", nil, "https://codeclimate.com") }
         | 
| 53 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 54 | 
            -
                  it { is_expected.to match_array(["skywinder", "ActionSheetPicker-3.0"]) }
         | 
| 55 | 
            -
                end
         | 
| 56 | 
            -
                context "when second arg is not nil" do
         | 
| 57 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", "blah", nil) }
         | 
| 58 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 59 | 
            -
                  it { is_expected.to match_array([nil, nil]) }
         | 
| 60 | 
            -
                end
         | 
| 61 | 
            -
                context "when all args is not nil" do
         | 
| 62 | 
            -
                  subject { GitHubChangelogGenerator::Parser.user_project_from_option("skywinder/ActionSheetPicker-3.0", "blah", "https://codeclimate.com") }
         | 
| 63 | 
            -
                  it { is_expected.to be_a(Array) }
         | 
| 64 | 
            -
                  it { is_expected.to match_array([nil, nil]) }
         | 
| 65 | 
            -
                end
         | 
| 66 | 
            -
              end
         | 
| 67 | 
            -
              describe ".fetch_user_and_project" do
         | 
| 68 | 
            -
                before do
         | 
| 69 | 
            -
                  stub_const("ARGV", ["https://github.com/skywinder/github-changelog-generator"])
         | 
| 70 | 
            -
                end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                context do
         | 
| 73 | 
            -
                  let(:valid_user) { "initialized_user" }
         | 
| 74 | 
            -
                  let(:options) { { user: valid_user } }
         | 
| 75 | 
            -
                  let(:options_before_change) { options.dup }
         | 
| 76 | 
            -
                  it "should leave user unchanged" do
         | 
| 77 | 
            -
                    expect { GitHubChangelogGenerator::Parser.fetch_user_and_project(options) }.to change { options }
         | 
| 78 | 
            -
                      .from(options_before_change)
         | 
| 79 | 
            -
                      .to(options_before_change.merge(project: "github-changelog-generator"))
         | 
| 80 | 
            -
                  end
         | 
| 81 | 
            -
                end
         | 
| 82 | 
            -
              end
         | 
| 83 4 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: github_changelog_generator
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.15.0.pre. | 
| 4 | 
            +
              version: 1.15.0.pre.beta
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Petr Korolev
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2017-10- | 
| 12 | 
            +
            date: 2017-10-13 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: rake
         |