Class: GitHubChangelogGenerator::Generator

Inherits:
Object
  • Object
show all
Defined in:
lib/github_changelog_generator/generator/generator.rb,
lib/github_changelog_generator/generator/generator_tags.rb,
lib/github_changelog_generator/generator/generator_fetcher.rb,
lib/github_changelog_generator/generator/generator_processor.rb

Overview

This class is the high-level code for gathering issues and PRs for a github repository and generating a CHANGELOG.md file. A changelog is made up of a series of “entries” of all tagged releases, plus an extra entry for the unreleased changes. Entries are made up of various organizational “sections,” and sections contain the github issues and PRs.

So the changelog contains entries, entries contain sections, and sections contain issues and PRs.

See Also:

Constant Summary collapse

CREDIT_LINE =
<<~CREDIT
  \\* *This Changelog was automatically generated \
  by [github_changelog_generator]\
  (https://github.com/github-changelog-generator/github-changelog-generator)*
CREDIT

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Generator

A Generator responsible for all logic, related with changelog generation from ready-to-parse issues

Example:

generator = GitHubChangelogGenerator::Generator.new
content = generator.compound_changelog


40
41
42
43
44
45
# File 'lib/github_changelog_generator/generator/generator.rb', line 40

def initialize(options = {})
  @options        = options
  @tag_times_hash = {}
  @fetcher        = GitHubChangelogGenerator::OctoFetcher.new(options)
  @sections       = []
end

Instance Attribute Details

#filtered_tagsObject

Returns the value of attribute filtered_tags.



27
28
29
# File 'lib/github_changelog_generator/generator/generator.rb', line 27

def filtered_tags
  @filtered_tags
end

#optionsObject

Returns the value of attribute options.



27
28
29
# File 'lib/github_changelog_generator/generator/generator.rb', line 27

def options
  @options
end

#sorted_tagsObject

Returns the value of attribute sorted_tags.



27
28
29
# File 'lib/github_changelog_generator/generator/generator.rb', line 27

def sorted_tags
  @sorted_tags
end

#tag_section_mappingObject

Returns the value of attribute tag_section_mapping.



27
28
29
# File 'lib/github_changelog_generator/generator/generator.rb', line 27

def tag_section_mapping
  @tag_section_mapping
end

Instance Method Details

#add_first_occurring_tag_to_prs(tags, prs) ⇒ Nil

Adds a key “first_occurring_tag” to each PR with a value of the oldest tag that a PR’s merge commit occurs in in the git history. This should indicate the release of each PR by git’s history regardless of dates and divergent branches.

Parameters:

  • tags (Array)

    The tags sorted by time, newest to oldest.

  • prs (Array)

    The PRs to discover the tags of.

Returns:

  • (Nil)

    No return; PRs are updated in-place.



45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 45

def add_first_occurring_tag_to_prs(tags, prs)
  total = prs.count

  prs_left = associate_tagged_prs(tags, prs, total)
  prs_left = associate_release_branch_prs(prs_left, total)
  prs_left = associate_rebase_comment_prs(tags, prs_left, total) if prs_left.any?
  # PRs in prs_left will be untagged, not in release branch, and not
  # rebased. They should not be included in the changelog as they probably
  # have been merged to a branch other than the release branch.
  @pull_requests -= prs_left
  Helper.log.info "Associating PRs with tags: #{total}/#{total}"
end

#associate_rebase_comment_prs(tags, prs_left, total) ⇒ Array

Associate merged PRs by the SHA detected in github comments of the form “rebased commit: <sha>”. For use when the merge_commit_sha is not in the actual git history due to rebase.

Parameters:

  • tags (Array)

    The tags sorted by time, newest to oldest.

  • prs_left (Array)

    The PRs not yet associated with any tag or branch.

Returns:

  • (Array)

    PRs without rebase comments.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 126

def associate_rebase_comment_prs(tags, prs_left, total)
  i = total - prs_left.count
  # Any remaining PRs were not found in the list of tags by their merge
  # commit and not found in any specified release branch. Fallback to
  # rebased commit comment.
  @fetcher.fetch_comments_async(prs_left)
  prs_left.reject do |pr|
    found = false
    if pr["comments"] && (rebased_comment = pr["comments"].reverse.find { |c| c["body"].match(%r{rebased commit: ([0-9a-f]{40})}i) })
      rebased_sha = rebased_comment["body"].match(%r{rebased commit: ([0-9a-f]{40})}i)[1]
      if (oldest_tag = tags.reverse.find { |tag| tag["shas_in_tag"].include?(rebased_sha) })
        pr["first_occurring_tag"] = oldest_tag["name"]
        found = true
        i += 1
      elsif sha_in_release_branch(rebased_sha)
        found = true
        i += 1
      else
        raise StandardError, "PR #{pr['number']} has a rebased SHA comment but that SHA was not found in the release branch or any tags"
      end
      print("Associating PRs with tags: #{i}/#{total}\r") if @options[:verbose]
    else
      puts "Warning: PR #{pr['number']} merge commit was not found in the release branch or tagged git history and no rebased SHA comment was found"
    end
    found
  end
end

#associate_release_branch_prs(prs_left, total) ⇒ Array

Associate merged PRs by the HEAD of the release branch. If no –release-branch was specified, then the github default branch is used.

Parameters:

  • prs_left (Array)

    PRs not associated with any tag.

  • total (Integer)

    The total number of PRs to associate; used for verbose printing.

Returns:

  • (Array)

    PRs without their merge_commit_sha in the branch.



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 102

def associate_release_branch_prs(prs_left, total)
  if prs_left.any?
    i = total - prs_left.count
    prs_left.reject do |pr|
      found = false
      if pr["events"] && (event = pr["events"].find { |e| e["event"] == "merged" }) && sha_in_release_branch(event["commit_id"])
        found = true
        i += 1
        print("Associating PRs with tags: #{i}/#{total}\r") if @options[:verbose]
      end
      found
    end
  else
    prs_left
  end
end

#associate_tagged_prs(tags, prs, total) ⇒ Array

Associate merged PRs by the merge SHA contained in each tag. If the merge_commit_sha is not found in any tag’s history, skip association.

Parameters:

  • tags (Array)

    The tags sorted by time, newest to oldest.

  • prs (Array)

    The PRs to associate.

Returns:

  • (Array)

    PRs without their merge_commit_sha in a tag.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 64

def associate_tagged_prs(tags, prs, total)
  @fetcher.fetch_tag_shas(tags)

  i = 0
  prs.reject do |pr|
    found = false
    # XXX Wish I could use merge_commit_sha, but gcg doesn't currently
    # fetch that. See
    # https://developer.github.com/v3/pulls/#get-a-single-pull-request vs.
    # https://developer.github.com/v3/pulls/#list-pull-requests
    if pr["events"] && (event = pr["events"].find { |e| e["event"] == "merged" })
      # Iterate tags.reverse (oldest to newest) to find first tag of each PR.
      if (oldest_tag = tags.reverse.find { |tag| tag["shas_in_tag"].include?(event["commit_id"]) })
        pr["first_occurring_tag"] = oldest_tag["name"]
        found = true
        i += 1
        print("Associating PRs with tags: #{i}/#{total}\r") if @options[:verbose]
      end
    else
      # Either there were no events or no merged event. Github's api can be
      # weird like that apparently. Check for a rebased comment before erroring.
      no_events_pr = associate_rebase_comment_prs(tags, [pr], total)
      raise StandardError, "No merge sha found for PR #{pr['number']} via the GitHub API" unless no_events_pr.empty?

      found = true
      i += 1
      print("Associating PRs with tags: #{i}/#{total}\r") if @options[:verbose]
    end
    found
  end
end

#build_tag_section_mapping(section_tags, filtered_tags) ⇒ Hash

PRs to include in this section will be >= [Left Tag Date] and <= [Right Tag Date] rubocop:disable Style/For - for allows us to be more concise

Parameters:

  • section_tags (Array)

    are the tags that need a subsection output

  • filtered_tags (Array)

    is the list of filtered tags ordered from newest -> oldest

Returns:

  • (Hash)

    key is the tag to output, value is an array of [Left Tag, Right Tag]



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 27

def build_tag_section_mapping(, filtered_tags)
  tag_mapping = {}
  for i in 0..(.length - 1)
    tag = [i]

    # Don't create section header for the "since" tag
    next if since_tag && tag["name"] == since_tag

    # Don't create a section header for the first tag in between_tags
    next if options[:between_tags] && tag == .last

    # Don't create a section header for excluded tags
    next unless filtered_tags.include?(tag)

    older_tag = [i + 1]
    tag_mapping[tag] = [older_tag, tag]
  end
  tag_mapping
end

#compound_changelogString

Main function to start changelog generation

Returns:

  • (String)

    Generated changelog file



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/github_changelog_generator/generator/generator.rb', line 50

def compound_changelog
  @options.load_custom_ruby_files

  Sync do
    fetch_and_filter_tags
    fetch_issues_and_pr

    log = if @options[:unreleased_only]
            generate_entry_between_tags(@filtered_tags[0], nil)
          else
            generate_entries_for_all_tags
          end
    log += File.read(@options[:base]) if File.file?(@options[:base])
    log = remove_old_fixed_string(log)
    log = insert_fixed_string(log)
    @log = log
  end
end

#delete_by_time(issues, hash_key = "actual_date", older_tag = nil, newer_tag = nil) ⇒ Array

Method filter issues, that belong only specified tag range

Parameters:

  • issues (Array)

    issues to filter

  • hash_key (Symbol) (defaults to: "actual_date")

    key of date value default is :actual_date

  • older_tag (Hash, Nil) (defaults to: nil)

    all issues before this tag date will be excluded. May be nil, if it’s first tag

  • newer_tag (Hash, Nil) (defaults to: nil)

    all issue after this tag will be excluded. May be nil for unreleased section

Returns:

  • (Array)

    filtered issues



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 99

def delete_by_time(issues, hash_key = "actual_date", older_tag = nil, newer_tag = nil)
  # in case if not tags specified - return unchanged array
  return issues if older_tag.nil? && newer_tag.nil?

  older_tag = ensure_older_tag(older_tag, newer_tag)

  newer_tag_time = newer_tag && get_time_of_tag(newer_tag)
  older_tag_time = older_tag && get_time_of_tag(older_tag)

  issues.select do |issue|
    if issue[hash_key]
      time = Time.parse(issue[hash_key].to_s).utc

      tag_in_range_old = tag_newer_old_tag?(older_tag_time, time)

      tag_in_range_new = tag_older_new_tag?(newer_tag_time, time)

      tag_in_range = tag_in_range_old && tag_in_range_new

      tag_in_range
    else
      false
    end
  end
end

#detect_actual_closed_dates(issues) ⇒ Object

Find correct closed dates, if issues was closed by commits



26
27
28
29
30
31
32
33
34
35
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 26

def detect_actual_closed_dates(issues)
  print "Fetching closed dates for issues...\r" if options[:verbose]

  i = 0
  issues.each do |issue|
    find_closed_date_by_commit(issue)
    i += 1
  end
  puts "Fetching closed dates for issues: #{i}/#{issues.count}" if options[:verbose]
end

Detect link, name and time for specified tag.

Parameters:

  • newer_tag (Hash)

    newer tag. Can be nil, if it’s Unreleased section.

Returns:

  • (Array)

    link, name and time of the tag



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 79

def detect_link_tag_time(newer_tag)
  # if tag is nil - set current time
  newer_tag_time = newer_tag.nil? ? Time.new.getutc : get_time_of_tag(newer_tag)

  # if it's future release tag - set this value
  if newer_tag.nil? && options[:future_release]
    newer_tag_name = options[:future_release]
    newer_tag_link = options[:future_release]
  else
    # put unreleased label if there is no name for the tag
    newer_tag_name = newer_tag.nil? ? options[:unreleased_label] : newer_tag["name"]
    newer_tag_link = newer_tag.nil? ? "HEAD" : newer_tag_name
  end
  [newer_tag_link, newer_tag_name, newer_tag_time]
end

#due_tagObject



100
101
102
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 100

def due_tag
  @due_tag ||= options.fetch(:due_tag, nil)
end

#ensure_older_tag(older_tag, newer_tag) ⇒ Object



125
126
127
128
129
130
131
132
133
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 125

def ensure_older_tag(older_tag, newer_tag)
  return older_tag if older_tag

  idx = sorted_tags.index { |t| t["name"] == newer_tag["name"] }
  # skip if we are already at the oldest element
  return if idx == sorted_tags.size - 1

  sorted_tags[idx - 1]
end

#exclude_issues_by_labels(issues) ⇒ Array

delete all issues with labels from options array

Parameters:

  • issues (Array)

Returns:

  • (Array)

    filtered array



8
9
10
11
12
13
14
15
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 8

def exclude_issues_by_labels(issues)
  return issues if !options[:exclude_labels] || options[:exclude_labels].empty?

  issues.reject do |issue|
    labels = issue["labels"].map { |l| l["name"] }
    (labels & options[:exclude_labels]).any?
  end
end

#exclude_issues_without_labels(issues) ⇒ Array

Only include issues without labels if options

Parameters:

  • issues (Array)

Returns:

  • (Array)

    filtered array



20
21
22
23
24
25
26
27
28
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 20

def exclude_issues_without_labels(issues)
  return issues if issues.empty?
  return issues if issues.first.key?("pull_request") && options[:add_pr_wo_labels]
  return issues if !issues.first.key?("pull_request") && options[:add_issues_wo_labels]

  issues.reject do |issue|
    issue["labels"].empty?
  end
end

#fetch_and_filter_tagsObject

fetch, filter tags, fetch dates and sort them in time order



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 6

def fetch_and_filter_tags
  since_tag
  due_tag

  all_tags = @fetcher.get_all_tags
  fetch_tags_dates(all_tags) # Creates a Hash @tag_times_hash
  all_sorted_tags = sort_tags_by_date(all_tags)

  @sorted_tags   = filter_included_tags(all_sorted_tags)
  @sorted_tags   = filter_excluded_tags(@sorted_tags)
  @filtered_tags = get_filtered_tags(@sorted_tags)
  @tag_section_mapping = build_tag_section_mapping(@filtered_tags, @filtered_tags)

  @filtered_tags
end

#fetch_events_for_issues_and_prArray

Fetch event for issues and pull requests

Returns:

  • (Array)

    array of fetched issues



7
8
9
10
11
12
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 7

def fetch_events_for_issues_and_pr
  print "Fetching events for issues and PR: 0/#{@issues.count + @pull_requests.count}\r" if options[:verbose]

  # Async fetching events:
  @fetcher.fetch_events_async(@issues + @pull_requests)
end

#fetch_tags_dates(tags) ⇒ Object

Async fetching of all tags dates



15
16
17
18
19
20
21
22
23
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 15

def fetch_tags_dates(tags)
  print "Fetching tag dates...\r" if options[:verbose]
  i = 0
  tags.each do |tag|
    get_time_of_tag(tag)
    i += 1
  end
  puts "Fetching tags dates: #{i}/#{tags.count}" if options[:verbose]
end

#filter_array_by_labels(all_issues) ⇒ Array

General filtered function

Parameters:

  • all_issues (Array)

    PRs or issues

Returns:

  • (Array)

    filtered issues



188
189
190
191
192
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 188

def filter_array_by_labels(all_issues)
  filtered_issues = include_issues_by_labels(all_issues)
  filtered_issues = exclude_issues_by_labels(filtered_issues)
  exclude_issues_without_labels(filtered_issues)
end

#filter_by_include_labels(issues) ⇒ Object



173
174
175
176
177
178
179
180
181
182
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 173

def filter_by_include_labels(issues)
  if options[:include_labels].nil?
    issues
  else
    issues.select do |issue|
      labels = issue["labels"].map { |l| l["name"] } & options[:include_labels]
      labels.any? || issue["labels"].empty?
    end
  end
end

#filter_by_milestone(filtered_issues, tag_name, all_issues) ⇒ Array

Returns filtered issues accourding milestone.

Returns:

  • (Array)

    filtered issues accourding milestone



31
32
33
34
35
36
37
38
39
40
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 31

def filter_by_milestone(filtered_issues, tag_name, all_issues)
  remove_issues_in_milestones(filtered_issues)
  unless tag_name.nil?
    # add missed issues (according milestones)
    issues_to_add = find_issues_to_add(all_issues, tag_name)

    filtered_issues |= issues_to_add
  end
  filtered_issues
end

#filter_by_tag(issues, newer_tag = nil) ⇒ Array

Method filter issues, that belong only specified tag range

Parameters:

  • issues (Array)

    issues to filter

  • newer_tag (Hash, Nil) (defaults to: nil)

    Tag to find PRs of. May be nil for unreleased section

Returns:

  • (Array)

    filtered issues



87
88
89
90
91
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 87

def filter_by_tag(issues, newer_tag = nil)
  issues.select do |issue|
    issue["first_occurring_tag"] == (newer_tag.nil? ? nil : newer_tag["name"])
  end
end

#filter_due_tag(all_tags) ⇒ Array

Returns filtered tags according :due_tag option.

Parameters:

  • all_tags (Array)

    all tags

Returns:

  • (Array)

    filtered tags according :due_tag option



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 141

def filter_due_tag(all_tags)
  filtered_tags = all_tags
  tag           = due_tag
  if tag
    if all_tags.any? && all_tags.map { |t| t["name"] }.include?(tag)
      idx = all_tags.index { |t| t["name"] == tag }
      filtered_tags = if idx > 0
                        all_tags[(idx + 1)..-1]
                      else
                        []
                      end
    else
      raise ChangelogGeneratorError, "Error: can't find tag #{tag}, specified with --due-tag option."
    end
  end
  filtered_tags
end

#filter_excluded_tags(all_tags) ⇒ Array

Returns filtered tags according :exclude_tags or :exclude_tags_regex option.

Parameters:

  • all_tags (Array)

    all tags

Returns:

  • (Array)

    filtered tags according :exclude_tags or :exclude_tags_regex option



172
173
174
175
176
177
178
179
180
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 172

def filter_excluded_tags(all_tags)
  if options[:exclude_tags]
    apply_exclude_tags(all_tags)
  elsif options[:exclude_tags_regex]
    apply_exclude_tags_regex(all_tags)
  else
    all_tags
  end
end

#filter_included_tags(all_tags) ⇒ Array

Returns filtered tags according to :include_tags_regex option.

Parameters:

  • all_tags (Array)

    all tags

Returns:

  • (Array)

    filtered tags according to :include_tags_regex option



161
162
163
164
165
166
167
168
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 161

def filter_included_tags(all_tags)
  if options[:include_tags_regex]
    regex = Regexp.new(options[:include_tags_regex])
    all_tags.select { |tag| regex =~ tag["name"] }
  else
    all_tags
  end
end

#filter_merged_pull_requests(pull_requests) ⇒ Object

This method filter only merged PR and fetch missing required attributes for pull requests :merged_at - is a date, when issue PR was merged. More correct to use merged date, rather than closed date.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 217

def filter_merged_pull_requests(pull_requests)
  print "Fetching merged dates...\r" if options[:verbose]
  closed_pull_requests = @fetcher.fetch_closed_pull_requests

  pull_requests.each do |pr|
    fetched_pr = closed_pull_requests.find do |fpr|
      fpr["number"] == pr["number"]
    end
    if fetched_pr
      pr["merged_at"] = fetched_pr["merged_at"]
      closed_pull_requests.delete(fetched_pr)
    end
  end

  pull_requests.reject! do |pr|
    pr["merged_at"].nil?
  end

  pull_requests
end

#filter_since_tag(all_tags) ⇒ Array

Returns filtered tags according :since_tag option.

Parameters:

  • all_tags (Array)

    all tags

Returns:

  • (Array)

    filtered tags according :since_tag option



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 121

def filter_since_tag(all_tags)
  filtered_tags = all_tags
  tag = since_tag
  if tag
    if all_tags.map { |t| t["name"] }.include? tag
      idx = all_tags.index { |t| t["name"] == tag }
      filtered_tags = if idx
                        all_tags[0..idx]
                      else
                        []
                      end
    else
      raise ChangelogGeneratorError, "Error: can't find tag #{tag}, specified with --since-tag option."
    end
  end
  filtered_tags
end

#filter_wo_labels(items) ⇒ Array

Returns Issues & PRs without labels or empty array if add_issues_wo_labels or add_pr_wo_labels are false.

Parameters:

  • issues (Array)

    Issues & PRs to filter when without labels

Returns:

  • (Array)

    Issues & PRs without labels or empty array if add_issues_wo_labels or add_pr_wo_labels are false



162
163
164
165
166
167
168
169
170
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 162

def filter_wo_labels(items)
  if items.any? && items.first.key?("pull_request")
    return items if options[:add_pr_wo_labels]
  elsif options[:add_issues_wo_labels]
    return items
  end
  # The default is to filter items without labels
  items.select { |item| item["labels"].map { |l| l["name"] }.any? }
end

#find_closed_date_by_commit(issue) ⇒ Object

Fill :actual_date parameter of specified issue by closed date of the commit, if it was closed by commit.

Parameters:

  • issue (Hash)


156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 156

def find_closed_date_by_commit(issue)
  unless issue["events"].nil?
    # if it's PR -> then find "merged event", in case of usual issue -> fond closed date
    compare_string = issue["merged_at"].nil? ? "closed" : "merged"
    # reverse! - to find latest closed event. (event goes in date order)
    issue["events"].reverse!.each do |event|
      if event["event"].eql? compare_string
        set_date_from_event(event, issue)
        break
      end
    end
  end
  # TODO: assert issues, that remain without 'actual_date' hash for some reason.
end

#find_issues_to_add(all_issues, tag_name) ⇒ Array

Add all issues, that should be in that tag, according milestone

Parameters:

  • all_issues (Array)
  • tag_name (String)

Returns:

  • (Array)

    issues with milestone #tag_name



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 47

def find_issues_to_add(all_issues, tag_name)
  all_issues.select do |issue|
    if issue["milestone"].nil?
      false
    else
      # check, that this milestone in tag list:
      milestone_is_tag = @filtered_tags.find do |tag|
        tag["name"] == issue["milestone"]["title"]
      end

      if milestone_is_tag.nil?
        false
      else
        issue["milestone"]["title"] == tag_name
      end
    end
  end
end

#get_filtered_issues(issues) ⇒ Array

Filter issues according labels

Returns:

  • (Array)

    Filtered issues



196
197
198
199
200
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 196

def get_filtered_issues(issues)
  issues = filter_array_by_labels(issues)
  puts "Filtered issues: #{issues.count}" if options[:verbose]
  issues
end

#get_filtered_pull_requests(pull_requests) ⇒ Array

This method fetches missing params for PR and filter them by specified options It include add all PR’s with labels from options array And exclude all from :exclude_labels array.

Returns:

  • (Array)

    filtered PR’s



206
207
208
209
210
211
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 206

def get_filtered_pull_requests(pull_requests)
  pull_requests = filter_array_by_labels(pull_requests)
  pull_requests = filter_merged_pull_requests(pull_requests)
  puts "Filtered pull requests: #{pull_requests.count}" if options[:verbose]
  pull_requests
end

#get_filtered_tags(all_tags) ⇒ Array

Return tags after filtering tags in lists provided by option: –exclude-tags

Returns:

  • (Array)


114
115
116
117
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 114

def get_filtered_tags(all_tags)
  filtered_tags = filter_since_tag(all_tags)
  filter_due_tag(filtered_tags)
end

#get_time_of_tag(tag_name) ⇒ Time

Returns date for given GitHub Tag hash

Memoize the date by tag name.

Parameters:

  • tag_name (Hash)

Returns:

  • (Time)

    time of specified tag

Raises:



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 63

def get_time_of_tag(tag_name)
  raise ChangelogGeneratorError, "tag_name is nil" if tag_name.nil?

  name_of_tag = tag_name.fetch("name")
  time_for_tag_name = @tag_times_hash[name_of_tag]
  return time_for_tag_name if time_for_tag_name

  @fetcher.fetch_date_of_tag(tag_name).tap do |time_string|
    @tag_times_hash[name_of_tag] = time_string
  end
end

#include_issues_by_labels(issues) ⇒ Array

Include issues with labels, specified in :include_labels

Parameters:

  • issues (Array)

    to filter

Returns:

  • (Array)

    filtered array of issues



154
155
156
157
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 154

def include_issues_by_labels(issues)
  filtered_issues = filter_by_include_labels(issues)
  filter_wo_labels(filtered_issues)
end

#remove_issues_in_milestones(filtered_issues) ⇒ Array

Returns array with removed issues, that contain milestones with same name as a tag.

Returns:

  • (Array)

    array with removed issues, that contain milestones with same name as a tag



67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 67

def remove_issues_in_milestones(filtered_issues)
  filtered_issues.select! do |issue|
    # leave issues without milestones
    if issue["milestone"].nil?
      true
    # remove issues of open milestones if option is set
    elsif issue["milestone"]["state"] == "open"
      @options[:issues_of_open_milestones]
    else
      # check, that this milestone in tag list:
      @filtered_tags.find { |tag| tag["name"] == issue["milestone"]["title"] }.nil?
    end
  end
end

#set_date_from_event(event, issue) ⇒ Object

Set closed date from this issue

Parameters:

  • event (Hash)
  • issue (Hash)


175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/github_changelog_generator/generator/generator_fetcher.rb', line 175

def set_date_from_event(event, issue)
  if event["commit_id"].nil?
    issue["actual_date"] = issue["closed_at"]
  else
    begin
      commit = @fetcher.fetch_commit(event["commit_id"])
      issue["actual_date"] = commit["commit"]["author"]["date"]

      # issue['actual_date'] = commit['author']['date']
    rescue StandardError
      puts "Warning: Can't fetch commit #{event['commit_id']}. It is probably referenced from another repo."
      issue["actual_date"] = issue["closed_at"]
    end
  end
end

#since_tagObject

Returns try to find newest tag using #Reader and :base option if specified otherwise returns nil.

Returns:

  • (Object)

    try to find newest tag using #Reader and :base option if specified otherwise returns nil



96
97
98
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 96

def since_tag
  @since_tag ||= options.fetch(:since_tag) { version_of_first_item }
end

#sort_tags_by_date(tags) ⇒ Object

Sort all tags by date, newest to oldest



49
50
51
52
53
54
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 49

def sort_tags_by_date(tags)
  puts "Sorting tags..." if options[:verbose]
  tags.sort_by! do |x|
    get_time_of_tag(x)
  end.reverse!
end

#tag_newer_old_tag?(older_tag_time, time) ⇒ Boolean

Returns:

  • (Boolean)


143
144
145
146
147
148
149
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 143

def tag_newer_old_tag?(older_tag_time, time)
  if older_tag_time.nil?
    true
  else
    time > older_tag_time
  end
end

#tag_older_new_tag?(newer_tag_time, time) ⇒ Boolean

Returns:

  • (Boolean)


135
136
137
138
139
140
141
# File 'lib/github_changelog_generator/generator/generator_processor.rb', line 135

def tag_older_new_tag?(newer_tag_time, time)
  if newer_tag_time.nil?
    true
  else
    time <= newer_tag_time
  end
end

#version_of_first_itemObject



104
105
106
107
108
109
# File 'lib/github_changelog_generator/generator/generator_tags.rb', line 104

def version_of_first_item
  return unless File.file?(options[:base].to_s)

  sections = GitHubChangelogGenerator::Reader.new.read(options[:base])
  sections.first["version"] if sections && sections.any?
end