github_changelog_generator 1.16.1 → 1.16.2
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/README.md +1 -1
- data/lib/github_changelog_generator/argv_parser.rb +224 -0
- data/lib/github_changelog_generator/generator/generator_fetcher.rb +4 -5
- data/lib/github_changelog_generator/generator/generator_processor.rb +2 -1
- data/lib/github_changelog_generator/octo_fetcher.rb +21 -4
- data/lib/github_changelog_generator/options.rb +1 -0
- data/lib/github_changelog_generator/parser.rb +70 -258
- data/lib/github_changelog_generator/parser_file.rb +28 -13
- data/lib/github_changelog_generator/ssl_certs/cacert.pem +851 -1680
- data/lib/github_changelog_generator/version.rb +1 -1
- data/man/git-generate-changelog.1 +31 -31
- data/man/git-generate-changelog.1.html +30 -30
- data/man/git-generate-changelog.html +19 -19
- data/man/git-generate-changelog.md +31 -31
- data/spec/files/config_example +5 -0
- data/spec/unit/parser_spec.rb +50 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ccac267908f4f46f4660f682da9b2d83f3b14e84f987a2c8929c59a928684e3
|
4
|
+
data.tar.gz: ca7866e9ebed6bbfe7dcfd637a63330dafec2d13602a47917faf84ff1cbde656
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d362fbc5862e8170d82175a6e9adf15eae99b578d894b7df7c15531e80326e17947a5c8f88d2964900a296d9760a53ef339d598de2cf2b703242fb391c805457
|
7
|
+
data.tar.gz: 3e38da7c8a091c7efc681c295f7d6467a227579cddff107a28f7a51a50c8d808008e012a457afd9faa6f92f2021dac648d634ab04aac4958acb54934f40085f5
|
data/README.md
CHANGED
@@ -84,7 +84,7 @@ Using [Docker](https://www.docker.com/products/docker-desktop) is an alternative
|
|
84
84
|
|
85
85
|
Example invocation:
|
86
86
|
|
87
|
-
$ docker run -it --rm -v "$(pwd)":/usr/local/src/your-app
|
87
|
+
$ docker run -it --rm -v "$(pwd)":/usr/local/src/your-app githubchangeloggenerator/github-changelog-generator
|
88
88
|
|
89
89
|
|
90
90
|
|
@@ -0,0 +1,224 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "github_changelog_generator/version"
|
5
|
+
|
6
|
+
module GitHubChangelogGenerator
|
7
|
+
class ArgvParser
|
8
|
+
attr_reader :options
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse!(argv)
|
15
|
+
parser.parse(argv)
|
16
|
+
rescue OptionParser::ParseError => e
|
17
|
+
warn [e, parser].join("\n")
|
18
|
+
Kernel.abort
|
19
|
+
end
|
20
|
+
|
21
|
+
def parser
|
22
|
+
@parser ||= OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
|
23
|
+
opts.banner = "Usage: github_changelog_generator --user USER --project PROJECT [options]"
|
24
|
+
opts.on("-u", "--user USER", "Username of the owner of the target GitHub repo OR the namespace of target Github repo if owned by an organization.") do |last|
|
25
|
+
options[:user] = last
|
26
|
+
end
|
27
|
+
opts.on("-p", "--project PROJECT", "Name of project on GitHub.") do |last|
|
28
|
+
options[:project] = last
|
29
|
+
end
|
30
|
+
opts.on("-t", "--token TOKEN", "To make more than 50 requests per hour your GitHub token is required. You can generate it at: https://github.com/settings/tokens/new") do |last|
|
31
|
+
options[:token] = last
|
32
|
+
end
|
33
|
+
opts.on("-f", "--date-format FORMAT", "Date format. Default is %Y-%m-%d.") do |last|
|
34
|
+
options[:date_format] = last
|
35
|
+
end
|
36
|
+
opts.on("-o", "--output NAME", "Output file. To print to STDOUT instead, use blank as path. Default is CHANGELOG.md") do |last|
|
37
|
+
options[:output] = last
|
38
|
+
end
|
39
|
+
opts.on("-b", "--base NAME", "Optional base file to append generated changes to. Default is HISTORY.md") do |last|
|
40
|
+
options[:base] = last
|
41
|
+
end
|
42
|
+
opts.on("--summary-label LABEL", "Set up custom label for the release summary section. Default is \"\".") do |v|
|
43
|
+
options[:summary_prefix] = v
|
44
|
+
end
|
45
|
+
opts.on("--breaking-label LABEL", "Set up custom label for the breaking changes section. Default is \"**Breaking changes:**\".") do |v|
|
46
|
+
options[:breaking_prefix] = v
|
47
|
+
end
|
48
|
+
opts.on("--enhancement-label LABEL", "Set up custom label for enhancements section. Default is \"**Implemented enhancements:**\".") do |v|
|
49
|
+
options[:enhancement_prefix] = v
|
50
|
+
end
|
51
|
+
opts.on("--bugs-label LABEL", "Set up custom label for bug-fixes section. Default is \"**Fixed bugs:**\".") do |v|
|
52
|
+
options[:bug_prefix] = v
|
53
|
+
end
|
54
|
+
opts.on("--deprecated-label LABEL", "Set up custom label for the deprecated changes section. Default is \"**Deprecated:**\".") do |v|
|
55
|
+
options[:deprecated_prefix] = v
|
56
|
+
end
|
57
|
+
opts.on("--removed-label LABEL", "Set up custom label for the removed changes section. Default is \"**Removed:**\".") do |v|
|
58
|
+
options[:removed_prefix] = v
|
59
|
+
end
|
60
|
+
opts.on("--security-label LABEL", "Set up custom label for the security changes section. Default is \"**Security fixes:**\".") do |v|
|
61
|
+
options[:security_prefix] = v
|
62
|
+
end
|
63
|
+
opts.on("--issues-label LABEL", "Set up custom label for closed-issues section. Default is \"**Closed issues:**\".") do |v|
|
64
|
+
options[:issue_prefix] = v
|
65
|
+
end
|
66
|
+
opts.on("--header-label LABEL", "Set up custom header label. Default is \"# Changelog\".") do |v|
|
67
|
+
options[:header] = v
|
68
|
+
end
|
69
|
+
opts.on("--configure-sections HASH, STRING", "Define your own set of sections which overrides all default sections.") do |v|
|
70
|
+
options[:configure_sections] = v
|
71
|
+
end
|
72
|
+
opts.on("--add-sections HASH, STRING", "Add new sections but keep the default sections.") do |v|
|
73
|
+
options[:add_sections] = v
|
74
|
+
end
|
75
|
+
opts.on("--front-matter JSON", "Add YAML front matter. Formatted as JSON because it's easier to add on the command line.") do |v|
|
76
|
+
options[:frontmatter] = "#{JSON.parse(v).to_yaml}---\n"
|
77
|
+
end
|
78
|
+
opts.on("--pr-label LABEL", "Set up custom label for pull requests section. Default is \"**Merged pull requests:**\".") do |v|
|
79
|
+
options[:merge_prefix] = v
|
80
|
+
end
|
81
|
+
opts.on("--[no-]issues", "Include closed issues in changelog. Default is true.") do |v|
|
82
|
+
options[:issues] = v
|
83
|
+
end
|
84
|
+
opts.on("--[no-]issues-wo-labels", "Include closed issues without labels in changelog. Default is true.") do |v|
|
85
|
+
options[:add_issues_wo_labels] = v
|
86
|
+
end
|
87
|
+
opts.on("--[no-]pr-wo-labels", "Include pull requests without labels in changelog. Default is true.") do |v|
|
88
|
+
options[:add_pr_wo_labels] = v
|
89
|
+
end
|
90
|
+
opts.on("--[no-]pull-requests", "Include pull-requests in changelog. Default is true.") do |v|
|
91
|
+
options[:pulls] = v
|
92
|
+
end
|
93
|
+
opts.on("--[no-]filter-by-milestone", "Use milestone to detect when issue was resolved. Default is true.") do |last|
|
94
|
+
options[:filter_issues_by_milestone] = last
|
95
|
+
end
|
96
|
+
opts.on("--[no-]issues-of-open-milestones", "Include issues of open milestones. Default is true.") do |v|
|
97
|
+
options[:issues_of_open_milestones] = v
|
98
|
+
end
|
99
|
+
opts.on("--[no-]author", "Add author of pull request at the end. Default is true.") do |author|
|
100
|
+
options[:author] = author
|
101
|
+
end
|
102
|
+
opts.on("--usernames-as-github-logins", "Use GitHub tags instead of Markdown links for the author of an issue or pull-request.") do |v|
|
103
|
+
options[:usernames_as_github_logins] = v
|
104
|
+
end
|
105
|
+
opts.on("--unreleased-only", "Generate log from unreleased closed issues only.") do |v|
|
106
|
+
options[:unreleased_only] = v
|
107
|
+
end
|
108
|
+
opts.on("--[no-]unreleased", "Add to log unreleased closed issues. Default is true.") do |v|
|
109
|
+
options[:unreleased] = v
|
110
|
+
end
|
111
|
+
opts.on("--unreleased-label LABEL", "Set up custom label for unreleased closed issues section. Default is \"**Unreleased:**\".") do |v|
|
112
|
+
options[:unreleased_label] = v
|
113
|
+
end
|
114
|
+
opts.on("--[no-]compare-link", "Include compare link (Full Changelog) between older version and newer version. Default is true.") do |v|
|
115
|
+
options[:compare_link] = v
|
116
|
+
end
|
117
|
+
opts.on("--include-labels x,y,z", Array, "Of the labeled issues, only include the ones with the specified labels.") do |list|
|
118
|
+
options[:include_labels] = list
|
119
|
+
end
|
120
|
+
opts.on("--exclude-labels x,y,z", Array, "Issues with the specified labels will be excluded from changelog. Default is 'duplicate,question,invalid,wontfix'.") do |list|
|
121
|
+
options[:exclude_labels] = list
|
122
|
+
end
|
123
|
+
opts.on("--summary-labels x,y,z", Array, 'Issues with these labels will be added to a new section, called "Release Summary". The section display only body of issues. Default is \'release-summary,summary\'.') do |list|
|
124
|
+
options[:summary_labels] = list
|
125
|
+
end
|
126
|
+
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,breaking\'.') do |list|
|
127
|
+
options[:breaking_labels] = list
|
128
|
+
end
|
129
|
+
opts.on("--enhancement-labels x,y,z", Array, 'Issues with the specified labels will be added to "Implemented enhancements" section. Default is \'enhancement,Enhancement\'.') do |list|
|
130
|
+
options[:enhancement_labels] = list
|
131
|
+
end
|
132
|
+
opts.on("--bug-labels x,y,z", Array, 'Issues with the specified labels will be added to "Fixed bugs" section. Default is \'bug,Bug\'.') do |list|
|
133
|
+
options[:bug_labels] = list
|
134
|
+
end
|
135
|
+
opts.on("--deprecated-labels x,y,z", Array, 'Issues with the specified labels will be added to a section called "Deprecated". Default is \'deprecated,Deprecated\'.') do |list|
|
136
|
+
options[:deprecated_labels] = list
|
137
|
+
end
|
138
|
+
opts.on("--removed-labels x,y,z", Array, 'Issues with the specified labels will be added to a section called "Removed". Default is \'removed,Removed\'.') do |list|
|
139
|
+
options[:removed_labels] = list
|
140
|
+
end
|
141
|
+
opts.on("--security-labels x,y,z", Array, 'Issues with the specified labels will be added to a section called "Security fixes". Default is \'security,Security\'.') do |list|
|
142
|
+
options[:security_labels] = list
|
143
|
+
end
|
144
|
+
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|
|
145
|
+
options[:issue_line_labels] = list
|
146
|
+
end
|
147
|
+
opts.on("--include-tags-regex REGEX", "Apply a regular expression on tag names so that they can be included, for example: --include-tags-regex \".*\+\d{1,}\".") do |last|
|
148
|
+
options[:include_tags_regex] = last
|
149
|
+
end
|
150
|
+
opts.on("--exclude-tags x,y,z", Array, "Changelog will exclude specified tags") do |list|
|
151
|
+
options[:exclude_tags] = list
|
152
|
+
end
|
153
|
+
opts.on("--exclude-tags-regex REGEX", "Apply a regular expression on tag names so that they can be excluded, for example: --exclude-tags-regex \".*\+\d{1,}\".") do |last|
|
154
|
+
options[:exclude_tags_regex] = last
|
155
|
+
end
|
156
|
+
opts.on("--since-tag x", "Changelog will start after specified tag.") do |v|
|
157
|
+
options[:since_tag] = v
|
158
|
+
end
|
159
|
+
opts.on("--due-tag x", "Changelog will end before specified tag.") do |v|
|
160
|
+
options[:due_tag] = v
|
161
|
+
end
|
162
|
+
opts.on("--since-commit x", "Fetch only commits after this time. eg. \"2017-01-01 10:00:00\"") do |v|
|
163
|
+
options[:since_commit] = v
|
164
|
+
end
|
165
|
+
opts.on("--max-issues NUMBER", Integer, "Maximum number of issues to fetch from GitHub. Default is unlimited.") do |max|
|
166
|
+
options[:max_issues] = max
|
167
|
+
end
|
168
|
+
opts.on("--release-url URL", "The URL to point to for release links, in printf format (with the tag as variable).") do |url|
|
169
|
+
options[:release_url] = url
|
170
|
+
end
|
171
|
+
opts.on("--github-site URL", "The Enterprise GitHub site where your project is hosted.") do |last|
|
172
|
+
options[:github_site] = last
|
173
|
+
end
|
174
|
+
opts.on("--github-api URL", "The enterprise endpoint to use for your GitHub API.") do |last|
|
175
|
+
options[:github_endpoint] = last
|
176
|
+
end
|
177
|
+
opts.on("--simple-list", "Create a simple list from issues and pull requests. Default is false.") do |v|
|
178
|
+
options[:simple_list] = v
|
179
|
+
end
|
180
|
+
opts.on("--future-release RELEASE-VERSION", "Put the unreleased changes in the specified release number.") do |future_release|
|
181
|
+
options[:future_release] = future_release
|
182
|
+
end
|
183
|
+
opts.on("--release-branch RELEASE-BRANCH", "Limit pull requests to the release branch, such as master or release.") do |release_branch|
|
184
|
+
options[:release_branch] = release_branch
|
185
|
+
end
|
186
|
+
opts.on("--[no-]http-cache", "Use HTTP Cache to cache GitHub API requests (useful for large repos). Default is true.") do |http_cache|
|
187
|
+
options[:http_cache] = http_cache
|
188
|
+
end
|
189
|
+
opts.on("--cache-file CACHE-FILE", "Filename to use for cache. Default is github-changelog-http-cache in a temporary directory.") do |cache_file|
|
190
|
+
options[:cache_file] = cache_file
|
191
|
+
end
|
192
|
+
opts.on("--cache-log CACHE-LOG", "Filename to use for cache log. Default is github-changelog-logger.log in a temporary directory.") do |cache_log|
|
193
|
+
options[:cache_log] = cache_log
|
194
|
+
end
|
195
|
+
opts.on("--config-file CONFIG-FILE", "Path to configuration file. Default is .github_changelog_generator.") do |config_file|
|
196
|
+
options[:config_file] = config_file
|
197
|
+
end
|
198
|
+
opts.on("--ssl-ca-file PATH", "Path to cacert.pem file. Default is a bundled lib/github_changelog_generator/ssl_certs/cacert.pem. Respects SSL_CA_PATH.") do |ssl_ca_file|
|
199
|
+
options[:ssl_ca_file] = ssl_ca_file
|
200
|
+
end
|
201
|
+
opts.on("--require x,y,z", Array, "Path to Ruby file(s) to require before generating changelog.") do |paths|
|
202
|
+
options[:require] = paths
|
203
|
+
end
|
204
|
+
opts.on("--[no-]verbose", "Run verbosely. Default is true.") do |v|
|
205
|
+
options[:verbose] = v
|
206
|
+
end
|
207
|
+
opts.on("-v", "--version", "Print version number.") do |_v|
|
208
|
+
puts "Version: #{GitHubChangelogGenerator::VERSION}"
|
209
|
+
exit
|
210
|
+
end
|
211
|
+
opts.on("-h", "--help", "Displays Help.") do
|
212
|
+
puts opts
|
213
|
+
exit
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class << self
|
219
|
+
def banner
|
220
|
+
new.parser.banner
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -104,7 +104,7 @@ module GitHubChangelogGenerator
|
|
104
104
|
i = total - prs_left.count
|
105
105
|
prs_left.reject do |pr|
|
106
106
|
found = false
|
107
|
-
if pr["events"] && (event = pr["events"].find { |e| e["event"] == "merged" }) && sha_in_release_branch(event["commit_id"])
|
107
|
+
if pr["events"] && (event = pr["events"].find { |e| e["event"] == "merged" }) && sha_in_release_branch?(event["commit_id"])
|
108
108
|
found = true
|
109
109
|
i += 1
|
110
110
|
print("Associating PRs with tags: #{i}/#{total}\r") if @options[:verbose]
|
@@ -137,7 +137,7 @@ module GitHubChangelogGenerator
|
|
137
137
|
pr["first_occurring_tag"] = oldest_tag["name"]
|
138
138
|
found = true
|
139
139
|
i += 1
|
140
|
-
elsif sha_in_release_branch(rebased_sha)
|
140
|
+
elsif sha_in_release_branch?(rebased_sha)
|
141
141
|
found = true
|
142
142
|
i += 1
|
143
143
|
else
|
@@ -195,10 +195,9 @@ module GitHubChangelogGenerator
|
|
195
195
|
#
|
196
196
|
# @param [String] sha SHA to check.
|
197
197
|
# @return [Boolean] True if SHA is in the branch git history.
|
198
|
-
def sha_in_release_branch(sha)
|
198
|
+
def sha_in_release_branch?(sha)
|
199
199
|
branch = @options[:release_branch] || @fetcher.default_branch
|
200
|
-
|
201
|
-
shas_in_branch.include?(sha)
|
200
|
+
@fetcher.commits_in_branch(branch).include?(sha)
|
202
201
|
end
|
203
202
|
end
|
204
203
|
end
|
@@ -156,7 +156,7 @@ module GitHubChangelogGenerator
|
|
156
156
|
filter_wo_labels(filtered_issues)
|
157
157
|
end
|
158
158
|
|
159
|
-
# @param [Array]
|
159
|
+
# @param [Array] items Issues & PRs to filter when without labels
|
160
160
|
# @return [Array] Issues & PRs without labels or empty array if
|
161
161
|
# add_issues_wo_labels or add_pr_wo_labels are false
|
162
162
|
def filter_wo_labels(items)
|
@@ -170,6 +170,7 @@ module GitHubChangelogGenerator
|
|
170
170
|
end
|
171
171
|
|
172
172
|
# @todo Document this
|
173
|
+
# @param [Object] issues
|
173
174
|
def filter_by_include_labels(issues)
|
174
175
|
if options[:include_labels].nil?
|
175
176
|
issues
|
@@ -105,6 +105,9 @@ module GitHubChangelogGenerator
|
|
105
105
|
# Returns the number of pages for a API call
|
106
106
|
#
|
107
107
|
# @return [Integer] number of pages for this API call in total
|
108
|
+
# @param [Object] request_options
|
109
|
+
# @param [Object] method
|
110
|
+
# @param [Object] client
|
108
111
|
def calculate_pages(client, method, request_options)
|
109
112
|
# Makes the first API call so that we can call last_response
|
110
113
|
check_github_response do
|
@@ -161,7 +164,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
161
164
|
page_i = 0
|
162
165
|
count_pages = calculate_pages(client, "issues", closed_pr_options)
|
163
166
|
|
164
|
-
iterate_pages(client, "issues", closed_pr_options) do |new_issues|
|
167
|
+
iterate_pages(client, "issues", **closed_pr_options) do |new_issues|
|
165
168
|
page_i += PER_PAGE_NUMBER
|
166
169
|
print_in_same_line("Fetching issues... #{page_i}/#{count_pages * PER_PAGE_NUMBER}")
|
167
170
|
issues.concat(new_issues)
|
@@ -185,7 +188,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
185
188
|
page_i = 0
|
186
189
|
count_pages = calculate_pages(client, "pull_requests", options)
|
187
190
|
|
188
|
-
iterate_pages(client, "pull_requests", options) do |new_pr|
|
191
|
+
iterate_pages(client, "pull_requests", **options) do |new_pr|
|
189
192
|
page_i += PER_PAGE_NUMBER
|
190
193
|
log_string = "Fetching merged dates... #{page_i}/#{count_pages * PER_PAGE_NUMBER}"
|
191
194
|
print_in_same_line(log_string)
|
@@ -215,7 +218,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
215
218
|
issues.each do |issue|
|
216
219
|
semaphore.async do
|
217
220
|
issue["events"] = []
|
218
|
-
iterate_pages(client, "issue_events", issue["number"], preview) do |new_event|
|
221
|
+
iterate_pages(client, "issue_events", issue["number"], **preview) do |new_event|
|
219
222
|
issue["events"].concat(new_event)
|
220
223
|
end
|
221
224
|
issue["events"] = issue["events"].map { |event| stringify_keys_deep(event.to_hash) }
|
@@ -335,11 +338,15 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
335
338
|
@default_branch ||= client.repository(user_project)[:default_branch]
|
336
339
|
end
|
337
340
|
|
341
|
+
# @param [String] name
|
342
|
+
# @return [Array<String>]
|
338
343
|
def commits_in_branch(name)
|
339
344
|
@branches ||= client.branches(user_project).map { |branch| [branch[:name], branch] }.to_h
|
340
345
|
|
341
346
|
if (branch = @branches[name])
|
342
347
|
commits_in_tag(branch[:commit][:sha])
|
348
|
+
else
|
349
|
+
[]
|
343
350
|
end
|
344
351
|
end
|
345
352
|
|
@@ -347,7 +354,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
347
354
|
# "shas_in_tag"
|
348
355
|
#
|
349
356
|
# @param [Array] tags The array of tags.
|
350
|
-
# @return
|
357
|
+
# @return void
|
351
358
|
def fetch_tag_shas(tags)
|
352
359
|
# Reverse the tags array to gain max benefit from the @commits_in_tag_cache
|
353
360
|
tags.reverse_each do |tag|
|
@@ -357,6 +364,8 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
357
364
|
|
358
365
|
private
|
359
366
|
|
367
|
+
# @param [Set] shas
|
368
|
+
# @param [Object] sha
|
360
369
|
def commits_in_tag(sha, shas = Set.new)
|
361
370
|
# Reduce multiple runs for the same tag
|
362
371
|
return @commits_in_tag_cache[sha] if @commits_in_tag_cache.key?(sha)
|
@@ -382,6 +391,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
382
391
|
shas
|
383
392
|
end
|
384
393
|
|
394
|
+
# @param [Object] indata
|
385
395
|
def stringify_keys_deep(indata)
|
386
396
|
case indata
|
387
397
|
when Array
|
@@ -405,10 +415,13 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
405
415
|
#
|
406
416
|
# @param [Octokit::Client] client
|
407
417
|
# @param [String] method (eg. 'tags')
|
418
|
+
# @param [Array] arguments
|
419
|
+
# @param [Async::Semaphore] parent
|
408
420
|
#
|
409
421
|
# @yield [Sawyer::Resource] An OctoKit-provided response (which can be empty)
|
410
422
|
#
|
411
423
|
# @return [void]
|
424
|
+
# @param [Hash] options
|
412
425
|
def iterate_pages(client, method, *arguments, parent: nil, **options)
|
413
426
|
options = DEFAULT_REQUEST_OPTIONS.merge(options)
|
414
427
|
|
@@ -442,6 +455,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
442
455
|
# This is wrapper with rescue block
|
443
456
|
#
|
444
457
|
# @return [Object] returns exactly the same, what you put in the block, but wrap it with begin-rescue block
|
458
|
+
# @param [Proc] block
|
445
459
|
def check_github_response(&block)
|
446
460
|
Retriable.retriable(retry_options, &block)
|
447
461
|
rescue MovedPermanentlyError => e
|
@@ -453,6 +467,8 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
453
467
|
end
|
454
468
|
|
455
469
|
# Presents the exception, and the aborts with the message.
|
470
|
+
# @param [Object] message
|
471
|
+
# @param [Object] error
|
456
472
|
def fail_with_message(error, message)
|
457
473
|
Helper.log.error("#{error.class}: #{error.message}")
|
458
474
|
sys_abort(message)
|
@@ -483,6 +499,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
483
499
|
end
|
484
500
|
end
|
485
501
|
|
502
|
+
# @param [Object] msg
|
486
503
|
def sys_abort(msg)
|
487
504
|
abort(msg)
|
488
505
|
end
|
@@ -1,277 +1,89 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "optparse"
|
5
|
-
require "github_changelog_generator/version"
|
6
4
|
require "github_changelog_generator/helper"
|
5
|
+
require "github_changelog_generator/argv_parser"
|
6
|
+
require "github_changelog_generator/parser_file"
|
7
7
|
|
8
8
|
module GitHubChangelogGenerator
|
9
9
|
class Parser
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
class << self
|
11
|
+
PARSERS = [
|
12
|
+
ArgvParser, # Parse arguments first to get initial options populated
|
13
|
+
FileParserChooser, # Then parse possible configuration files
|
14
|
+
ArgvParser # Lastly parse arguments again to keep the given arguments the strongest
|
15
|
+
].freeze
|
13
16
|
|
14
|
-
|
17
|
+
def parse_options(argv = ARGV)
|
18
|
+
options = default_options
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
abort [e, parser].join("\n")
|
20
|
-
end
|
20
|
+
PARSERS.each do |parser|
|
21
|
+
parser.new(options).parse!(argv)
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
abort_if_user_and_project_not_given!(options)
|
25
|
+
|
26
|
+
options.print_options
|
27
|
+
|
28
|
+
options
|
26
29
|
end
|
27
30
|
|
28
|
-
options
|
31
|
+
def abort_if_user_and_project_not_given!(options)
|
32
|
+
return if options[:user] && options[:project]
|
29
33
|
|
30
|
-
|
31
|
-
|
34
|
+
warn "Configure which user and project to work on."
|
35
|
+
warn "Options --user and --project, or settings to that effect. See --help for more."
|
36
|
+
warn ArgvParser.banner
|
32
37
|
|
33
|
-
|
34
|
-
#
|
35
|
-
# @param options [Options]
|
36
|
-
# @return [OptionParser]
|
37
|
-
def self.setup_parser(options)
|
38
|
-
OptionParser.new do |opts| # rubocop:disable Metrics/BlockLength
|
39
|
-
opts.banner = "Usage: github_changelog_generator --user USER --project PROJECT [options]"
|
40
|
-
opts.on("-u", "--user USER", "Username of the owner of the target GitHub repo OR the namespace of target Github repo if owned by an organization.") do |last|
|
41
|
-
options[:user] = last
|
42
|
-
end
|
43
|
-
opts.on("-p", "--project PROJECT", "Name of project on GitHub.") do |last|
|
44
|
-
options[:project] = last
|
45
|
-
end
|
46
|
-
opts.on("-t", "--token [TOKEN]", "To make more than 50 requests per hour your GitHub token is required. You can generate it at: https://github.com/settings/tokens/new") do |last|
|
47
|
-
options[:token] = last
|
48
|
-
end
|
49
|
-
opts.on("-f", "--date-format FORMAT", "Date format. Default is %Y-%m-%d.") do |last|
|
50
|
-
options[:date_format] = last
|
51
|
-
end
|
52
|
-
opts.on("-o", "--output [NAME]", "Output file. To print to STDOUT instead, use blank as path. Default is CHANGELOG.md") do |last|
|
53
|
-
options[:output] = last
|
54
|
-
end
|
55
|
-
opts.on("-b", "--base [NAME]", "Optional base file to append generated changes to.") do |last|
|
56
|
-
options[:base] = last
|
57
|
-
end
|
58
|
-
opts.on("--summary-label [LABEL]", "Set up custom label for the release summary section. Default is \"\".") do |v|
|
59
|
-
options[:summary_prefix] = v
|
60
|
-
end
|
61
|
-
opts.on("--breaking-label [LABEL]", "Set up custom label for the breaking changes section. Default is \"**Breaking changes:**\".") do |v|
|
62
|
-
options[:breaking_prefix] = v
|
63
|
-
end
|
64
|
-
opts.on("--enhancement-label [LABEL]", "Set up custom label for enhancements section. Default is \"**Implemented enhancements:**\".") do |v|
|
65
|
-
options[:enhancement_prefix] = v
|
66
|
-
end
|
67
|
-
opts.on("--bugs-label [LABEL]", "Set up custom label for bug-fixes section. Default is \"**Fixed bugs:**\".") do |v|
|
68
|
-
options[:bug_prefix] = v
|
69
|
-
end
|
70
|
-
opts.on("--deprecated-label [LABEL]", "Set up custom label for the deprecated changes section. Default is \"**Deprecated:**\".") do |v|
|
71
|
-
options[:deprecated_prefix] = v
|
72
|
-
end
|
73
|
-
opts.on("--removed-label [LABEL]", "Set up custom label for the removed changes section. Default is \"**Removed:**\".") do |v|
|
74
|
-
options[:removed_prefix] = v
|
75
|
-
end
|
76
|
-
opts.on("--security-label [LABEL]", "Set up custom label for the security changes section. Default is \"**Security fixes:**\".") do |v|
|
77
|
-
options[:security_prefix] = v
|
78
|
-
end
|
79
|
-
opts.on("--issues-label [LABEL]", "Set up custom label for closed-issues section. Default is \"**Closed issues:**\".") do |v|
|
80
|
-
options[:issue_prefix] = v
|
81
|
-
end
|
82
|
-
opts.on("--header-label [LABEL]", "Set up custom header label. Default is \"# Changelog\".") do |v|
|
83
|
-
options[:header] = v
|
84
|
-
end
|
85
|
-
opts.on("--configure-sections [Hash, String]", "Define your own set of sections which overrides all default sections.") do |v|
|
86
|
-
options[:configure_sections] = v
|
87
|
-
end
|
88
|
-
opts.on("--add-sections [Hash, String]", "Add new sections but keep the default sections.") do |v|
|
89
|
-
options[:add_sections] = v
|
90
|
-
end
|
91
|
-
opts.on("--front-matter [JSON]", "Add YAML front matter. Formatted as JSON because it's easier to add on the command line.") do |v|
|
92
|
-
options[:frontmatter] = "#{JSON.parse(v).to_yaml}---\n"
|
93
|
-
end
|
94
|
-
opts.on("--pr-label [LABEL]", "Set up custom label for pull requests section. Default is \"**Merged pull requests:**\".") do |v|
|
95
|
-
options[:merge_prefix] = v
|
96
|
-
end
|
97
|
-
opts.on("--[no-]issues", "Include closed issues in changelog. Default is true.") do |v|
|
98
|
-
options[:issues] = v
|
99
|
-
end
|
100
|
-
opts.on("--[no-]issues-wo-labels", "Include closed issues without labels in changelog. Default is true.") do |v|
|
101
|
-
options[:add_issues_wo_labels] = v
|
102
|
-
end
|
103
|
-
opts.on("--[no-]pr-wo-labels", "Include pull requests without labels in changelog. Default is true.") do |v|
|
104
|
-
options[:add_pr_wo_labels] = v
|
105
|
-
end
|
106
|
-
opts.on("--[no-]pull-requests", "Include pull-requests in changelog. Default is true.") do |v|
|
107
|
-
options[:pulls] = v
|
108
|
-
end
|
109
|
-
opts.on("--[no-]filter-by-milestone", "Use milestone to detect when issue was resolved. Default is true.") do |last|
|
110
|
-
options[:filter_issues_by_milestone] = last
|
111
|
-
end
|
112
|
-
opts.on("--[no-]issues-of-open-milestones", "Include issues of open milestones. Default is true.") do |v|
|
113
|
-
options[:issues_of_open_milestones] = v
|
114
|
-
end
|
115
|
-
opts.on("--[no-]author", "Add author of pull request at the end. Default is true.") do |author|
|
116
|
-
options[:author] = author
|
117
|
-
end
|
118
|
-
opts.on("--usernames-as-github-logins", "Use GitHub tags instead of Markdown links for the author of an issue or pull-request.") do |v|
|
119
|
-
options[:usernames_as_github_logins] = v
|
120
|
-
end
|
121
|
-
opts.on("--unreleased-only", "Generate log from unreleased closed issues only.") do |v|
|
122
|
-
options[:unreleased_only] = v
|
123
|
-
end
|
124
|
-
opts.on("--[no-]unreleased", "Add to log unreleased closed issues. Default is true.") do |v|
|
125
|
-
options[:unreleased] = v
|
126
|
-
end
|
127
|
-
opts.on("--unreleased-label [label]", "Set up custom label for unreleased closed issues section. Default is \"**Unreleased:**\".") do |v|
|
128
|
-
options[:unreleased_label] = v
|
129
|
-
end
|
130
|
-
opts.on("--[no-]compare-link", "Include compare link (Full Changelog) between older version and newer version. Default is true.") do |v|
|
131
|
-
options[:compare_link] = v
|
132
|
-
end
|
133
|
-
opts.on("--include-labels x,y,z", Array, "Of the labeled issues, only include the ones with the specified labels.") do |list|
|
134
|
-
options[:include_labels] = list
|
135
|
-
end
|
136
|
-
opts.on("--exclude-labels x,y,z", Array, "Issues with the specified labels will be excluded from changelog. Default is 'duplicate,question,invalid,wontfix'.") do |list|
|
137
|
-
options[:exclude_labels] = list
|
138
|
-
end
|
139
|
-
opts.on("--summary-labels x,y,z", Array, 'Issues with these labels will be added to a new section, called "Release Summary". The section display only body of issues. Default is \'release-summary,summary\'.') do |list|
|
140
|
-
options[:summary_labels] = list
|
141
|
-
end
|
142
|
-
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,breaking\'.') do |list|
|
143
|
-
options[:breaking_labels] = list
|
144
|
-
end
|
145
|
-
opts.on("--enhancement-labels x,y,z", Array, 'Issues with the specified labels will be added to "Implemented enhancements" section. Default is \'enhancement,Enhancement\'.') do |list|
|
146
|
-
options[:enhancement_labels] = list
|
147
|
-
end
|
148
|
-
opts.on("--bug-labels x,y,z", Array, 'Issues with the specified labels will be added to "Fixed bugs" section. Default is \'bug,Bug\'.') do |list|
|
149
|
-
options[:bug_labels] = list
|
150
|
-
end
|
151
|
-
opts.on("--deprecated-labels x,y,z", Array, 'Issues with the specified labels will be added to a section called "Deprecated". Default is \'deprecated,Deprecated\'.') do |list|
|
152
|
-
options[:deprecated_labels] = list
|
153
|
-
end
|
154
|
-
opts.on("--removed-labels x,y,z", Array, 'Issues with the specified labels will be added to a section called "Removed". Default is \'removed,Removed\'.') do |list|
|
155
|
-
options[:removed_labels] = list
|
156
|
-
end
|
157
|
-
opts.on("--security-labels x,y,z", Array, 'Issues with the specified labels will be added to a section called "Security fixes". Default is \'security,Security\'.') do |list|
|
158
|
-
options[:security_labels] = list
|
159
|
-
end
|
160
|
-
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|
|
161
|
-
options[:issue_line_labels] = list
|
162
|
-
end
|
163
|
-
opts.on("--include-tags-regex [REGEX]", "Apply a regular expression on tag names so that they can be included, for example: --include-tags-regex \".*\+\d{1,}\".") do |last|
|
164
|
-
options[:include_tags_regex] = last
|
165
|
-
end
|
166
|
-
opts.on("--exclude-tags x,y,z", Array, "Changelog will exclude specified tags") do |list|
|
167
|
-
options[:exclude_tags] = list
|
168
|
-
end
|
169
|
-
opts.on("--exclude-tags-regex [REGEX]", "Apply a regular expression on tag names so that they can be excluded, for example: --exclude-tags-regex \".*\+\d{1,}\".") do |last|
|
170
|
-
options[:exclude_tags_regex] = last
|
171
|
-
end
|
172
|
-
opts.on("--since-tag x", "Changelog will start after specified tag.") do |v|
|
173
|
-
options[:since_tag] = v
|
174
|
-
end
|
175
|
-
opts.on("--due-tag x", "Changelog will end before specified tag.") do |v|
|
176
|
-
options[:due_tag] = v
|
177
|
-
end
|
178
|
-
opts.on("--since-commit x", "Fetch only commits after this time. eg. \"2017-01-01 10:00:00\"") do |v|
|
179
|
-
options[:since_commit] = v
|
180
|
-
end
|
181
|
-
opts.on("--max-issues [NUMBER]", Integer, "Maximum number of issues to fetch from GitHub. Default is unlimited.") do |max|
|
182
|
-
options[:max_issues] = max
|
183
|
-
end
|
184
|
-
opts.on("--release-url [URL]", "The URL to point to for release links, in printf format (with the tag as variable).") do |url|
|
185
|
-
options[:release_url] = url
|
186
|
-
end
|
187
|
-
opts.on("--github-site [URL]", "The Enterprise GitHub site where your project is hosted.") do |last|
|
188
|
-
options[:github_site] = last
|
189
|
-
end
|
190
|
-
opts.on("--github-api [URL]", "The enterprise endpoint to use for your GitHub API.") do |last|
|
191
|
-
options[:github_endpoint] = last
|
192
|
-
end
|
193
|
-
opts.on("--simple-list", "Create a simple list from issues and pull requests. Default is false.") do |v|
|
194
|
-
options[:simple_list] = v
|
195
|
-
end
|
196
|
-
opts.on("--future-release [RELEASE-VERSION]", "Put the unreleased changes in the specified release number.") do |future_release|
|
197
|
-
options[:future_release] = future_release
|
198
|
-
end
|
199
|
-
opts.on("--release-branch [RELEASE-BRANCH]", "Limit pull requests to the release branch, such as master or release.") do |release_branch|
|
200
|
-
options[:release_branch] = release_branch
|
201
|
-
end
|
202
|
-
opts.on("--[no-]http-cache", "Use HTTP Cache to cache GitHub API requests (useful for large repos). Default is true.") do |http_cache|
|
203
|
-
options[:http_cache] = http_cache
|
204
|
-
end
|
205
|
-
opts.on("--cache-file [CACHE-FILE]", "Filename to use for cache. Default is github-changelog-http-cache in a temporary directory.") do |cache_file|
|
206
|
-
options[:cache_file] = cache_file
|
207
|
-
end
|
208
|
-
opts.on("--cache-log [CACHE-LOG]", "Filename to use for cache log. Default is github-changelog-logger.log in a temporary directory.") do |cache_log|
|
209
|
-
options[:cache_log] = cache_log
|
210
|
-
end
|
211
|
-
opts.on("--ssl-ca-file [PATH]", "Path to cacert.pem file. Default is a bundled lib/github_changelog_generator/ssl_certs/cacert.pem. Respects SSL_CA_PATH.") do |ssl_ca_file|
|
212
|
-
options[:ssl_ca_file] = ssl_ca_file
|
213
|
-
end
|
214
|
-
opts.on("--require x,y,z", Array, "Path to Ruby file(s) to require before generating changelog.") do |paths|
|
215
|
-
options[:require] = paths
|
216
|
-
end
|
217
|
-
opts.on("--[no-]verbose", "Run verbosely. Default is true.") do |v|
|
218
|
-
options[:verbose] = v
|
219
|
-
end
|
220
|
-
opts.on("-v", "--version", "Print version number.") do |_v|
|
221
|
-
puts "Version: #{GitHubChangelogGenerator::VERSION}"
|
222
|
-
exit
|
223
|
-
end
|
224
|
-
opts.on("-h", "--help", "Displays Help.") do
|
225
|
-
puts opts
|
226
|
-
exit
|
227
|
-
end
|
38
|
+
Kernel.abort
|
228
39
|
end
|
229
|
-
end
|
230
40
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
41
|
+
# @return [Options] Default options
|
42
|
+
def default_options
|
43
|
+
Options.new(
|
44
|
+
date_format: "%Y-%m-%d",
|
45
|
+
output: "CHANGELOG.md",
|
46
|
+
base: "HISTORY.md",
|
47
|
+
issues: true,
|
48
|
+
add_issues_wo_labels: true,
|
49
|
+
add_pr_wo_labels: true,
|
50
|
+
pulls: true,
|
51
|
+
filter_issues_by_milestone: true,
|
52
|
+
issues_of_open_milestones: true,
|
53
|
+
author: true,
|
54
|
+
unreleased: true,
|
55
|
+
unreleased_label: "Unreleased",
|
56
|
+
compare_link: true,
|
57
|
+
exclude_labels: ["duplicate", "question", "invalid", "wontfix", "Duplicate", "Question", "Invalid", "Wontfix", "Meta: Exclude From Changelog"],
|
58
|
+
summary_labels: ["Release summary", "release-summary", "Summary", "summary"],
|
59
|
+
breaking_labels: ["backwards-incompatible", "Backwards incompatible", "breaking"],
|
60
|
+
enhancement_labels: ["enhancement", "Enhancement", "Type: Enhancement"],
|
61
|
+
bug_labels: ["bug", "Bug", "Type: Bug"],
|
62
|
+
deprecated_labels: ["deprecated", "Deprecated", "Type: Deprecated"],
|
63
|
+
removed_labels: ["removed", "Removed", "Type: Removed"],
|
64
|
+
security_labels: ["security", "Security", "Type: Security"],
|
65
|
+
configure_sections: {},
|
66
|
+
add_sections: {},
|
67
|
+
issue_line_labels: [],
|
68
|
+
max_issues: nil,
|
69
|
+
simple_list: false,
|
70
|
+
ssl_ca_file: nil,
|
71
|
+
verbose: true,
|
72
|
+
header: "# Changelog",
|
73
|
+
merge_prefix: "**Merged pull requests:**",
|
74
|
+
issue_prefix: "**Closed issues:**",
|
75
|
+
summary_prefix: "",
|
76
|
+
breaking_prefix: "**Breaking changes:**",
|
77
|
+
enhancement_prefix: "**Implemented enhancements:**",
|
78
|
+
bug_prefix: "**Fixed bugs:**",
|
79
|
+
deprecated_prefix: "**Deprecated:**",
|
80
|
+
removed_prefix: "**Removed:**",
|
81
|
+
security_prefix: "**Security fixes:**",
|
82
|
+
http_cache: true,
|
83
|
+
require: [],
|
84
|
+
config_file: ".github_changelog_generator"
|
85
|
+
)
|
86
|
+
end
|
275
87
|
end
|
276
88
|
end
|
277
89
|
end
|