Skip to content

Commit

Permalink
Merge branch 'master' into 588-add-newline-after-credits
Browse files Browse the repository at this point in the history
  • Loading branch information
qwerty2323 authored May 24, 2018
2 parents f31347e + 984ee50 commit 37b5cae
Show file tree
Hide file tree
Showing 24 changed files with 1,048 additions and 440 deletions.
11 changes: 6 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ before_install:
matrix:
fast_finish: true
include:
- rvm: 2.2.7
- rvm: 2.2.9
install: true # This skips 'bundle install'
script: gem build github_changelog_generator && gem install *.gem
after_success: true # This skips 'codeclimate-test-reporter'
- rvm: 2.2.7
- rvm: 2.2.9
install: true # This skips 'bundle install'
script: gem build github_changelog_generator && bundle install
gemfile: spec/install-gem-in-bundler.gemfile
after_success: true # This skips 'codeclimate-test-reporter'
- rvm: 2.3.4
- rvm: 2.4.1
- rvm: jruby-9.1.15.0
- rvm: 2.3.6
- rvm: 2.4.3
- rvm: 2.5.0
- rvm: jruby-9.1.17.0
jdk: oraclejdk8
env:
- JRUBY_OPTS=--debug
Expand Down
1 change: 1 addition & 0 deletions .yardopts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
--markup=markdown
--plugin junk

16 changes: 0 additions & 16 deletions Dockerfile

This file was deleted.

1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ group :development, :test do
gem "overcommit", ">= 0.31"
gem "rake"
gem "rubocop", ">= 0.50"
gem "yard-junk"
end

group :development do
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ See also Troubleshooting.

## Running with Docker

$ docker run -it --rm -v "$(pwd)":/usr/local/src/your-app skywinder/github-changelog-generator
$ docker run -it --rm -v "$(pwd)":/usr/local/src/your-app ferrarimarco/github-changelog-generator

## Output example

Expand Down Expand Up @@ -84,11 +84,11 @@ See also Troubleshooting.
- Run this:

$ github_changelog_generator -u github_username -p github_project

or, on the 1.14.x (current stable release)

$ github_changelog_generator github_username/github_project


- For Github Enterprise repos, specify *both* `--github-site` and `--github-api` options:

Expand Down Expand Up @@ -164,6 +164,8 @@ Configure the task in your `Rakefile`:
require 'github_changelog_generator/task'

GitHubChangelogGenerator::RakeTask.new :changelog do |config|
config.user = 'username'
config.project = 'project-name'
config.since_tag = '0.1.14'
config.future_release = '0.2.0'
end
Expand All @@ -177,7 +179,7 @@ You can look for params names from the [parser source code (#setup_parser)](http

## Features and advantages of this project

- Generate canonical, neat changelog file, followed by [basic changelog guidelines](http://keepachangelog.com) :gem:
- Generate canonical, neat changelog file, with default sections that follow [basic changelog guidelines](http://keepachangelog.com) :gem:
- Optionally generate **Unreleased** changes (closed issues that have not released yet) :dizzy:
- **GitHub Enterprise support** via command line options! :factory:
- Flexible format **customization**:
Expand Down
2 changes: 1 addition & 1 deletion github_changelog_generator.gemspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

lib = File.expand_path("../lib", __FILE__)
lib = File.expand_path("lib", __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "github_changelog_generator/version"

Expand Down
5 changes: 4 additions & 1 deletion lib/github_changelog_generator/generator/entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ def default_sections
[
Section.new(name: "breaking", prefix: @options[:breaking_prefix], labels: @options[:breaking_labels], options: @options),
Section.new(name: "enhancements", prefix: @options[:enhancement_prefix], labels: @options[:enhancement_labels], options: @options),
Section.new(name: "bugs", prefix: @options[:bug_prefix], labels: @options[:bug_labels], options: @options)
Section.new(name: "bugs", prefix: @options[:bug_prefix], labels: @options[:bug_labels], options: @options),
Section.new(name: "deprecated", prefix: @options[:deprecated_prefix], labels: @options[:deprecated_labels], options: @options),
Section.new(name: "removed", prefix: @options[:removed_prefix], labels: @options[:removed_labels], options: @options),
Section.new(name: "security", prefix: @options[:security_prefix], labels: @options[:security_labels], options: @options)
]
end

Expand Down
28 changes: 17 additions & 11 deletions lib/github_changelog_generator/generator/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,21 @@ def initialize(options = {})
#
# @return [String] Generated changelog file
def compound_changelog
options.load_custom_ruby_files
@options.load_custom_ruby_files
fetch_and_filter_tags
fetch_issues_and_pr

log = ""
log += options[:frontmatter] if options[:frontmatter]
log += @options[:frontmatter] if @options[:frontmatter]
log += "#{options[:header]}\n\n"

log += if options[:unreleased_only]
generate_entry_between_tags(filtered_tags[0], nil)
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 += File.read(@options[:base]) if File.file?(@options[:base])

credit_line = "\n\n\\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*"
log.gsub!(/#{credit_line}(\n)?/, "") # Remove old credit lines
Expand Down Expand Up @@ -84,21 +84,22 @@ def generate_entry_between_tags(older_tag, newer_tag)
# the SHA for the first commit.
older_tag_name =
if older_tag.nil?
@fetcher.commits_before(newer_tag_time).last["sha"]
@fetcher.oldest_commit["sha"]
else
older_tag["name"]
end

Entry.new(options).generate_entry_for_tag(filtered_pull_requests, filtered_issues, newer_tag_name, newer_tag_link, newer_tag_time, older_tag_name)
end

# Filters issues and pull requests based on, respectively, `closed_at` and `merged_at`
# timestamp fields.
# Filters issues and pull requests based on, respectively, `actual_date`
# and `merged_at` timestamp fields. `actual_date` is the detected form of
# `closed_at` based on merge event SHA commit times.
#
# @return [Array] filtered issues and pull requests
def filter_issues_for_tags(newer_tag, older_tag)
filtered_pull_requests = delete_by_time(@pull_requests, "merged_at", older_tag, newer_tag)
filtered_issues = delete_by_time(@issues, "closed_at", older_tag, newer_tag)
filtered_pull_requests = filter_by_tag(@pull_requests, newer_tag)
filtered_issues = delete_by_time(@issues, "actual_date", older_tag, newer_tag)

newer_tag_name = newer_tag.nil? ? nil : newer_tag["name"]

Expand Down Expand Up @@ -128,13 +129,16 @@ def generate_entries_for_all_tags
def generate_unreleased_entry
entry = ""
if options[:unreleased]
start_tag = filtered_tags[0] || sorted_tags.last
start_tag = @filtered_tags[0] || @sorted_tags.last
unreleased_entry = generate_entry_between_tags(start_tag, nil)
entry += unreleased_entry if unreleased_entry
end
entry
end

# Fetches @pull_requests and @issues and filters them based on options.
#
# @return [Nil] No return.
def fetch_issues_and_pr
issues, pull_requests = @fetcher.fetch_closed_issues_and_pr

Expand All @@ -144,6 +148,8 @@ def fetch_issues_and_pr

fetch_events_for_issues_and_pr
detect_actual_closed_dates(@issues + @pull_requests)
add_first_occurring_tag_to_prs(@sorted_tags, @pull_requests)
nil
end
end
end
156 changes: 138 additions & 18 deletions lib/github_changelog_generator/generator/generator_fetcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,140 @@ def fetch_events_for_issues_and_pr
# Async fetching of all tags dates
def fetch_tags_dates(tags)
print "Fetching tag dates...\r" if options[:verbose]
# Async fetching tags:
threads = []
i = 0
all = tags.count
tags.each do |tag|
print " \r"
threads << Thread.new do
get_time_of_tag(tag)
print "Fetching tags dates: #{i + 1}/#{all}\r" if options[:verbose]
i += 1
end
get_time_of_tag(tag)
i += 1
end
threads.each(&:join)
puts "Fetching tags dates: #{i}" if options[:verbose]
puts "Fetching tags dates: #{i}/#{tags.count}" if options[:verbose]
end

# Find correct closed dates, if issues was closed by commits
def detect_actual_closed_dates(issues)
print "Fetching closed dates for issues...\r" if options[:verbose]

issues.each_slice(MAX_THREAD_NUMBER) do |issues_slice|
threads = []
issues_slice.each do |issue|
threads << Thread.new { find_closed_date_by_commit(issue) }
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

# 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.
#
# @param [Array] tags The tags sorted by time, newest to oldest.
# @param [Array] prs The PRs to discover the tags of.
# @return [Nil] No return; PRs are updated in-place.
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 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.
#
# @param [Array] tags The tags sorted by time, newest to oldest.
# @param [Array] prs The PRs to associate.
# @return [Array] PRs without their merge_commit_sha in a tag.
def associate_tagged_prs(tags, prs, total)
@fetcher.fetch_tag_shas_async(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

# Associate merged PRs by the HEAD of the release branch. If no
# --release-branch was specified, then the github default branch is used.
#
# @param [Array] prs_left PRs not associated with any tag.
# @param [Integer] total The total number of PRs to associate; used for verbose printing.
# @return [Array] PRs without their merge_commit_sha in the branch.
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 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.
#
# @param [Array] tags The tags sorted by time, newest to oldest.
# @param [Array] prs_left The PRs not yet associated with any tag or branch.
# @return [Array] PRs without rebase comments.
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
threads.each(&:join)
found
end
puts "Fetching closed dates for issues: Done!" if options[:verbose]
end

# Fill :actual_date parameter of specified issue by closed date of the commit, if it was closed by commit.
Expand Down Expand Up @@ -74,7 +180,7 @@ def set_date_from_event(event, issue)
issue["actual_date"] = issue["closed_at"]
else
begin
commit = @fetcher.fetch_commit(event)
commit = @fetcher.fetch_commit(event["commit_id"])
issue["actual_date"] = commit["commit"]["author"]["date"]

# issue['actual_date'] = commit['author']['date']
Expand All @@ -84,5 +190,19 @@ def set_date_from_event(event, issue)
end
end
end

private

# Detect if a sha occurs in the --release-branch. Uses the github repo
# default branch if not specified.
#
# @param [String] sha SHA to check.
# @return [Boolean] True if SHA is in the branch git history.
def sha_in_release_branch(sha)
branch = @options[:release_branch] || @fetcher.default_branch
commits_in_branch = @fetcher.fetch_compare(@fetcher.oldest_commit["sha"], branch)
shas_in_branch = commits_in_branch["commits"].collect { |commit| commit["sha"] }
shas_in_branch.include?(sha)
end
end
end
Loading

0 comments on commit 37b5cae

Please sign in to comment.