changelogerator 0.9.0 → 0.10.0
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/bin/changelogerator +12 -4
- data/lib/change.rb +40 -0
- data/lib/changelogerator.rb +51 -35
- data/lib/label.rb +41 -0
- metadata +10 -5
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a765967f91e3865aebe4990566bd73cdd310fde94ceade67ca4523486712752c
         | 
| 4 | 
            +
              data.tar.gz: 722f348d22b0a44270a6289f1bcf9b48ecb4b5197e6b6f61eddd552058572ea5
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8331c26720ae5168575df385006c13d06dcf592b0250d97bd9d846d8f3cb697a5b82ddbf198fe180422d6e54dc5b05b0cba5a193c16cfc75bcf1849179d553ac
         | 
| 7 | 
            +
              data.tar.gz: 9e7b6297c51b47965b103d5ba378a0cdbed04d1fe9cfa7f9190ed79f3d98a538945144bb75ffa78ddf1d71e276dd156f9fd455efb6ab08023e0daf0e7401ac1a
         | 
    
        data/bin/changelogerator
    CHANGED
    
    | @@ -16,12 +16,13 @@ logger.level = Logger::WARN | |
| 16 16 | 
             
            logger.debug('Starting')
         | 
| 17 17 |  | 
| 18 18 | 
             
            OptionParser.new do |opts|
         | 
| 19 | 
            -
              opts.banner =  | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 19 | 
            +
              opts.banner = 'Changelogerator
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            This utility helps generate a template friendly context made
         | 
| 22 | 
            +
            of the changes between 2 references on your Github project.
         | 
| 22 23 |  | 
| 23 24 | 
             
              Usage:
         | 
| 24 | 
            -
              changelogerator <repo> [options] | 
| 25 | 
            +
              changelogerator <repo> [options]'
         | 
| 25 26 |  | 
| 26 27 | 
             
              opts.on('-v', '--[no-]verbose', 'Run verbosely') do |v|
         | 
| 27 28 | 
             
                @options[:verbose] = v
         | 
| @@ -43,6 +44,13 @@ OptionParser.new do |opts| | |
| 43 44 | 
             
                puts opts
         | 
| 44 45 | 
             
                exit
         | 
| 45 46 | 
             
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              opts.on('-V', '--version', 'Show the version') do
         | 
| 49 | 
            +
                gemspec = "#{__dir__}/../changelogerator.gemspec"
         | 
| 50 | 
            +
                gem = Gem::Specification.load(gemspec)
         | 
| 51 | 
            +
                puts format('%<n>s v%<v>s', { v: gem.version, n: gem.name })
         | 
| 52 | 
            +
                exit
         | 
| 53 | 
            +
              end
         | 
| 46 54 | 
             
            end.parse!
         | 
| 47 55 |  | 
| 48 56 | 
             
            @options[:repo] = ARGV[0]
         | 
    
        data/lib/change.rb
    ADDED
    
    | @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'label'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ### A class describe one change that can potentially have several labels
         | 
| 6 | 
            +
            class Change
         | 
| 7 | 
            +
              attr_reader :labels
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def initialize(labels)
         | 
| 10 | 
            +
                # Below we test if we got the full data from Octokit or
         | 
| 11 | 
            +
                # only some fake data (label names only) from our tests.
         | 
| 12 | 
            +
                @labels = labels.map do |label|
         | 
| 13 | 
            +
                  if label.respond_to?(:name)
         | 
| 14 | 
            +
                    from_octokit(label)
         | 
| 15 | 
            +
                  else
         | 
| 16 | 
            +
                    from_str(label)
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                @extra = {}
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def []=(key, value)
         | 
| 24 | 
            +
                @extra[key] = value
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              def meta
         | 
| 28 | 
            +
                @extra['meta']
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              private
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def from_octokit(label)
         | 
| 34 | 
            +
                Label.new(label.name)
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              def from_str(label_name)
         | 
| 38 | 
            +
                Label.new(label_name)
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
    
        data/lib/changelogerator.rb
    CHANGED
    
    | @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require ' | 
| 3 | 
            +
            require 'label'
         | 
| 4 | 
            +
            require 'change'
         | 
| 4 5 |  | 
| 5 6 | 
             
            # A small wrapper class for more easily generating and manipulating Github/Git
         | 
| 6 7 | 
             
            # changelogs. Given two different git objects (sha, tag, whatever), it will
         | 
| @@ -34,13 +35,19 @@ class Changelog | |
| 34 35 | 
             
                  change._links = nil
         | 
| 35 36 |  | 
| 36 37 | 
             
                  change[:meta].each_key do |meta_key|
         | 
| 37 | 
            -
                     | 
| 38 | 
            -
             | 
| 39 | 
            -
                     | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
                     | 
| 38 | 
            +
                    aggregate = change[:meta][meta_key]['agg']
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    if meta[meta_key]
         | 
| 41 | 
            +
                      meta[meta_key][:min] = aggregate['min'] if aggregate['min'] < meta[meta_key][:min]
         | 
| 42 | 
            +
                      meta[meta_key][:max] = aggregate['max'] if aggregate['max'] > meta[meta_key][:max]
         | 
| 43 | 
            +
                      meta[meta_key][:count] += aggregate['count']
         | 
| 44 | 
            +
                    else
         | 
| 45 | 
            +
                      meta[meta_key] = {
         | 
| 46 | 
            +
                        min: aggregate['min'],
         | 
| 47 | 
            +
                        max: aggregate['max'],
         | 
| 48 | 
            +
                        count: aggregate['count']
         | 
| 49 | 
            +
                      }
         | 
| 50 | 
            +
                    end
         | 
| 44 51 | 
             
                  end
         | 
| 45 52 | 
             
                end
         | 
| 46 53 | 
             
              end
         | 
| @@ -56,18 +63,6 @@ class Changelog | |
| 56 63 | 
             
                nil
         | 
| 57 64 | 
             
              end
         | 
| 58 65 |  | 
| 59 | 
            -
              # Return the label code for a change
         | 
| 60 | 
            -
              # if the label name matches the expected pattern.
         | 
| 61 | 
            -
              # nil otherwise.
         | 
| 62 | 
            -
              def self.get_label_code(name)
         | 
| 63 | 
            -
                m = match = name.match(/^([a-z])(\d+)-(.*)$/i)
         | 
| 64 | 
            -
                if m
         | 
| 65 | 
            -
                  letter, number, text = match.captures
         | 
| 66 | 
            -
                  return [letter, number, text]
         | 
| 67 | 
            -
                end
         | 
| 68 | 
            -
                nil
         | 
| 69 | 
            -
              end
         | 
| 70 | 
            -
             | 
| 71 66 | 
             
              ## End of class methods
         | 
| 72 67 |  | 
| 73 68 | 
             
              # github_repo: 'paritytech/polkadot'
         | 
| @@ -84,16 +79,18 @@ class Changelog | |
| 84 79 | 
             
                )
         | 
| 85 80 | 
             
                @repository = @gh.repository(@repo)
         | 
| 86 81 | 
             
                @prefix = prefix
         | 
| 87 | 
            -
                 | 
| 82 | 
            +
                ids = pr_ids_from_git_diff(from, to)
         | 
| 83 | 
            +
                # The following takes very long time
         | 
| 84 | 
            +
                @changes = prs_from_ids(ids)
         | 
| 88 85 | 
             
                @changes.map do |c|
         | 
| 89 | 
            -
                  compute_change_meta(c)
         | 
| 86 | 
            +
                  self.class.compute_change_meta(c)
         | 
| 90 87 | 
             
                end
         | 
| 91 88 |  | 
| 92 89 | 
             
                compute_global_meta
         | 
| 93 90 | 
             
              end
         | 
| 94 91 |  | 
| 95 92 | 
             
              def add(change)
         | 
| 96 | 
            -
                compute_change_meta(change)
         | 
| 93 | 
            +
                self.class.compute_change_meta(change)
         | 
| 97 94 | 
             
                prettify_title(change)
         | 
| 98 95 | 
             
                changes.prepend(change)
         | 
| 99 96 | 
             
                @meta = compute_global_meta
         | 
| @@ -124,25 +121,41 @@ class Changelog | |
| 124 121 | 
             
                JSON.fast_generate(commits, opts)
         | 
| 125 122 | 
             
              end
         | 
| 126 123 |  | 
| 127 | 
            -
              private
         | 
| 128 | 
            -
             | 
| 129 124 | 
             
              # Compute and attach metadata about one change
         | 
| 130 | 
            -
              def compute_change_meta(change)
         | 
| 125 | 
            +
              def self.compute_change_meta(change)
         | 
| 131 126 | 
             
                meta = {}
         | 
| 132 127 |  | 
| 133 | 
            -
                change.labels.each do | | 
| 134 | 
            -
                   | 
| 135 | 
            -
             | 
| 128 | 
            +
                change.labels.each do |lbl|
         | 
| 129 | 
            +
                  label = Label.new(lbl.name)
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  next unless label
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  if meta.key?(label.letter)
         | 
| 134 | 
            +
                    aggregate = meta[label.letter]['agg']
         | 
| 135 | 
            +
                    aggregate['max'] = label.number if label.number > aggregate['max']
         | 
| 136 | 
            +
                    aggregate['min'] = label.number if label.number < aggregate['min']
         | 
| 137 | 
            +
                    aggregate['count'] += 1
         | 
| 138 | 
            +
                  else
         | 
| 139 | 
            +
                    meta[label.letter] = {
         | 
| 140 | 
            +
                      'agg' => {
         | 
| 141 | 
            +
                        'count' => 1,
         | 
| 142 | 
            +
                        'max' => label.number,
         | 
| 143 | 
            +
                        'min' => label.number
         | 
| 144 | 
            +
                      }
         | 
| 145 | 
            +
                    }
         | 
| 146 | 
            +
                  end
         | 
| 136 147 |  | 
| 137 | 
            -
                  meta[letter] = {
         | 
| 138 | 
            -
                    value | 
| 139 | 
            -
                    text | 
| 148 | 
            +
                  meta[label.letter]["#{label.letter}#{label.number}"] = {
         | 
| 149 | 
            +
                    'value' => label.number,
         | 
| 150 | 
            +
                    'text' => label.description
         | 
| 140 151 | 
             
                  }
         | 
| 141 152 | 
             
                end
         | 
| 142 153 |  | 
| 143 154 | 
             
                change['meta'] = meta
         | 
| 144 155 | 
             
              end
         | 
| 145 156 |  | 
| 157 | 
            +
              private
         | 
| 158 | 
            +
             | 
| 146 159 | 
             
              # Prepend the repo if @prefix is true
         | 
| 147 160 | 
             
              def prettify_title(pull)
         | 
| 148 161 | 
             
                pull[:pretty_title] = if @prefix
         | 
| @@ -154,14 +167,17 @@ class Changelog | |
| 154 167 | 
             
              end
         | 
| 155 168 |  | 
| 156 169 | 
             
              def pr_ids_from_git_diff(from, to)
         | 
| 157 | 
            -
                @gh.compare(@repo, from, to).commits | 
| 170 | 
            +
                commits = @gh.compare(@repo, from, to).commits
         | 
| 171 | 
            +
                commits.map do |c|
         | 
| 158 172 | 
             
                  title = c.commit.message.split("\n\n").first
         | 
| 159 | 
            -
                   | 
| 173 | 
            +
                  regex = /.*#([0-9]+).*$/
         | 
| 174 | 
            +
                  next unless title =~ regex
         | 
| 160 175 |  | 
| 161 | 
            -
                  title.gsub( | 
| 176 | 
            +
                  title.gsub(regex, '\1')
         | 
| 162 177 | 
             
                end.compact.map(&:to_i)
         | 
| 163 178 | 
             
              end
         | 
| 164 179 |  | 
| 180 | 
            +
              # TODO: See if we can make this quicker
         | 
| 165 181 | 
             
              def prs_from_ids(ids)
         | 
| 166 182 | 
             
                batch_size = 100
         | 
| 167 183 | 
             
                prs = []
         | 
    
        data/lib/label.rb
    ADDED
    
    | @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            ### Label = Letter + Number [+ Description]
         | 
| 4 | 
            +
            class Label
         | 
| 5 | 
            +
              attr_accessor :letter, :number, :description
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              # Return the label letter for a change if the label name matches the expected pattern.
         | 
| 8 | 
            +
              # nil otherwise.
         | 
| 9 | 
            +
              def parse(label)
         | 
| 10 | 
            +
                m = match = label.match(/^([a-z])(\d+)\s*-?\s*(.*)$/i)
         | 
| 11 | 
            +
                return nil unless m
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                letter, digits, text = match.captures
         | 
| 14 | 
            +
                number = digits.to_i
         | 
| 15 | 
            +
                [letter, number, text]
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def initialize(input)
         | 
| 19 | 
            +
                raise InvalidInput, 'Invalid, it must be a non-empty string' unless input
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                p = parse(input)
         | 
| 22 | 
            +
                raise InvalidLabel, format('Invalid label "%<input>s"', { input: input }) unless p
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                @letter = p[0].upcase
         | 
| 25 | 
            +
                @number = p[1]
         | 
| 26 | 
            +
                @description = p[2] unless p[2].empty?
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              ### Implemented for compatibility reasons
         | 
| 30 | 
            +
              def name
         | 
| 31 | 
            +
                to_str
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def to_str
         | 
| 35 | 
            +
                format('%<l>s%<n>d - %<d>s', { l: @letter, n: @number, d: @description })
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            class InvalidLabel < StandardError; end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            class InvalidInput < StandardError; end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,15 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: changelogerator
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.10.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Martin Pugh
         | 
| 8 | 
            +
            - Wilfried Kopp
         | 
| 8 9 | 
             
            autorequire:
         | 
| 9 10 | 
             
            bindir: bin
         | 
| 10 11 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 12 | 
            +
            date: 2023-02-15 00:00:00.000000000 Z
         | 
| 12 13 | 
             
            dependencies:
         | 
| 13 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 15 | 
             
              name: git_diff_parser
         | 
| @@ -38,7 +39,8 @@ dependencies: | |
| 38 39 | 
             
                - - "~>"
         | 
| 39 40 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 41 | 
             
                    version: '4'
         | 
| 41 | 
            -
            description:  | 
| 42 | 
            +
            description: A utility to fetch the data required to generate a changelog based on
         | 
| 43 | 
            +
              change in Github and formatted labels.
         | 
| 42 44 | 
             
            email:
         | 
| 43 45 | 
             
            executables:
         | 
| 44 46 | 
             
            - changelogerator
         | 
| @@ -46,11 +48,14 @@ extensions: [] | |
| 46 48 | 
             
            extra_rdoc_files: []
         | 
| 47 49 | 
             
            files:
         | 
| 48 50 | 
             
            - bin/changelogerator
         | 
| 51 | 
            +
            - lib/change.rb
         | 
| 49 52 | 
             
            - lib/changelogerator.rb
         | 
| 53 | 
            +
            - lib/label.rb
         | 
| 50 54 | 
             
            homepage: https://github.com/s3krit/changelogerator
         | 
| 51 55 | 
             
            licenses:
         | 
| 52 56 | 
             
            - AGPL-3.0
         | 
| 53 | 
            -
            metadata: | 
| 57 | 
            +
            metadata:
         | 
| 58 | 
            +
              rubygems_mfa_required: 'true'
         | 
| 54 59 | 
             
            post_install_message:
         | 
| 55 60 | 
             
            rdoc_options: []
         | 
| 56 61 | 
             
            require_paths:
         | 
| @@ -66,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 66 71 | 
             
                - !ruby/object:Gem::Version
         | 
| 67 72 | 
             
                  version: '0'
         | 
| 68 73 | 
             
            requirements: []
         | 
| 69 | 
            -
            rubygems_version: 3.2. | 
| 74 | 
            +
            rubygems_version: 3.2.33
         | 
| 70 75 | 
             
            signing_key:
         | 
| 71 76 | 
             
            specification_version: 4
         | 
| 72 77 | 
             
            summary: Changelog generation/management
         |