github_changelog_generator 1.16.3 → 1.17.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/README.md +52 -16
- data/bin/github_changelog_generator +1 -1
- data/lib/github_changelog_generator/argv_parser.rb +2 -2
- data/lib/github_changelog_generator/file_parser_chooser.rb +27 -0
- data/lib/github_changelog_generator/generator/entry.rb +3 -3
- data/lib/github_changelog_generator/generator/generator.rb +15 -10
- data/lib/github_changelog_generator/generator/generator_fetcher.rb +22 -24
- data/lib/github_changelog_generator/generator/generator_processor.rb +14 -24
- data/lib/github_changelog_generator/generator/generator_tags.rb +24 -34
- data/lib/github_changelog_generator/generator/section.rb +9 -4
- data/lib/github_changelog_generator/octo_fetcher.rb +38 -36
- data/lib/github_changelog_generator/options.rb +12 -2
- data/lib/github_changelog_generator/parser.rb +4 -4
- data/lib/github_changelog_generator/parser_file.rb +0 -24
- data/lib/github_changelog_generator/reader.rb +3 -1
- data/lib/github_changelog_generator/ssl_certs/cacert.pem +2 -78
- data/lib/github_changelog_generator/task.rb +2 -2
- data/lib/github_changelog_generator/version.rb +1 -1
- data/lib/github_changelog_generator.rb +18 -16
- data/man/git-generate-changelog.html +2 -2
- data/spec/github_changelog_generator_spec.rb +32 -0
- data/spec/unit/generator/entry_spec.rb +2 -2
- data/spec/unit/generator/generator_processor_spec.rb +61 -0
- data/spec/unit/generator/generator_spec.rb +151 -0
- data/spec/unit/generator/generator_tags_spec.rb +1 -1
- data/spec/unit/generator/section_spec.rb +9 -0
- data/spec/unit/octo_fetcher_spec.rb +8 -11
- data/spec/unit/{parse_file_spec.rb → parser_file_spec.rb} +35 -15
- data/spec/unit/reader_spec.rb +9 -0
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits/when_API_is_valid/returns_commits.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits_before/when_API_is_valid/returns_commits.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issue_with_proper_key/values.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues_with_labels.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_pull_request_with_proper_key/values.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_pull_requests_with_labels.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_correct_pull_request_keys.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_pull_requests.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid/returns_commit.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid/returns_date.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid/populates_issues.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags_count.json +1 -1
- data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid.json +1 -1
- metadata +12 -23
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "tmpdir"
|
|
4
|
-
require "retriable"
|
|
5
|
-
require "set"
|
|
6
4
|
require "async"
|
|
7
5
|
require "async/barrier"
|
|
8
6
|
require "async/semaphore"
|
|
@@ -60,7 +58,7 @@ module GitHubChangelogGenerator
|
|
|
60
58
|
end
|
|
61
59
|
|
|
62
60
|
builder.use Octokit::Response::RaiseError
|
|
63
|
-
builder.adapter
|
|
61
|
+
builder.adapter Faraday.default_adapter
|
|
64
62
|
end
|
|
65
63
|
end
|
|
66
64
|
|
|
@@ -96,12 +94,17 @@ module GitHubChangelogGenerator
|
|
|
96
94
|
# Fetch all tags from repo
|
|
97
95
|
#
|
|
98
96
|
# @return [Array <Hash>] array of tags
|
|
99
|
-
def
|
|
97
|
+
def fetch_all_tags
|
|
100
98
|
print "Fetching tags...\r" if @options[:verbose]
|
|
101
99
|
|
|
102
100
|
check_github_response { github_fetch_tags }
|
|
103
101
|
end
|
|
104
102
|
|
|
103
|
+
def get_all_tags # rubocop:disable Naming/AccessorMethodName
|
|
104
|
+
warn("[DEPRECATED] GitHubChangelogGenerator::OctoFetcher#get_all_tags is deprecated; use fetch_all_tags instead.")
|
|
105
|
+
fetch_all_tags
|
|
106
|
+
end
|
|
107
|
+
|
|
105
108
|
# Returns the number of pages for a API call
|
|
106
109
|
#
|
|
107
110
|
# @return [Integer] number of pages for this API call in total
|
|
@@ -306,12 +309,13 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
|
306
309
|
barrier = Async::Barrier.new
|
|
307
310
|
semaphore = Async::Semaphore.new(MAXIMUM_CONNECTIONS, parent: barrier)
|
|
308
311
|
|
|
312
|
+
branch = @options[:release_branch] || default_branch
|
|
309
313
|
if (since_commit = @options[:since_commit])
|
|
310
|
-
iterate_pages(client, "commits_since", since_commit, parent: semaphore) do |new_commits|
|
|
314
|
+
iterate_pages(client, "commits_since", since_commit, branch, parent: semaphore) do |new_commits|
|
|
311
315
|
@commits.concat(new_commits)
|
|
312
316
|
end
|
|
313
317
|
else
|
|
314
|
-
iterate_pages(client, "commits", parent: semaphore) do |new_commits|
|
|
318
|
+
iterate_pages(client, "commits", branch, parent: semaphore) do |new_commits|
|
|
315
319
|
@commits.concat(new_commits)
|
|
316
320
|
end
|
|
317
321
|
end
|
|
@@ -341,7 +345,13 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
|
341
345
|
# @param [String] name
|
|
342
346
|
# @return [Array<String>]
|
|
343
347
|
def commits_in_branch(name)
|
|
344
|
-
@branches ||=
|
|
348
|
+
@branches ||= lambda do
|
|
349
|
+
iterate_pages(client, "branches") do |branches|
|
|
350
|
+
branches_map = branches.to_h { |branch| [branch[:name], branch] }
|
|
351
|
+
return branches_map if branches_map[name]
|
|
352
|
+
end
|
|
353
|
+
{}
|
|
354
|
+
end.call
|
|
345
355
|
|
|
346
356
|
if (branch = @branches[name])
|
|
347
357
|
commits_in_tag(branch[:commit][:sha])
|
|
@@ -376,9 +386,15 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
|
376
386
|
queue = [current]
|
|
377
387
|
while queue.any?
|
|
378
388
|
commit = queue.shift
|
|
379
|
-
# If we've already processed this sha, just grab it's parents from the cache
|
|
380
389
|
if @commits_in_tag_cache.key?(commit[:sha])
|
|
390
|
+
# If we've already processed this sha in a previous run, just grab
|
|
391
|
+
# its parents from the cache
|
|
381
392
|
shas.merge(@commits_in_tag_cache[commit[:sha]])
|
|
393
|
+
elsif shas.include?(commit[:sha])
|
|
394
|
+
# If we've already processed this sha in the current run, stop there
|
|
395
|
+
# for the current commit because its parents have already been
|
|
396
|
+
# queued/processed. Jump to the next queued commit.
|
|
397
|
+
next
|
|
382
398
|
else
|
|
383
399
|
shas.add(commit[:sha])
|
|
384
400
|
commit[:parents].each do |p|
|
|
@@ -456,10 +472,21 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
|
456
472
|
#
|
|
457
473
|
# @return [Object] returns exactly the same, what you put in the block, but wrap it with begin-rescue block
|
|
458
474
|
# @param [Proc] block
|
|
459
|
-
def check_github_response
|
|
460
|
-
|
|
475
|
+
def check_github_response
|
|
476
|
+
yield
|
|
461
477
|
rescue MovedPermanentlyError => e
|
|
462
478
|
fail_with_message(e, "The repository has moved, update your configuration")
|
|
479
|
+
rescue Octokit::TooManyRequests => e
|
|
480
|
+
resets_in = client.rate_limit.resets_in
|
|
481
|
+
Helper.log.error("#{e.class} #{e.message}; sleeping for #{resets_in}s...")
|
|
482
|
+
|
|
483
|
+
if (task = Async::Task.current?)
|
|
484
|
+
task.sleep(resets_in)
|
|
485
|
+
else
|
|
486
|
+
sleep(resets_in)
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
retry
|
|
463
490
|
rescue Octokit::Forbidden => e
|
|
464
491
|
fail_with_message(e, "Exceeded retry limit")
|
|
465
492
|
rescue Octokit::Unauthorized => e
|
|
@@ -474,31 +501,6 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
|
474
501
|
sys_abort(message)
|
|
475
502
|
end
|
|
476
503
|
|
|
477
|
-
# Exponential backoff
|
|
478
|
-
def retry_options
|
|
479
|
-
{
|
|
480
|
-
on: [Octokit::Forbidden],
|
|
481
|
-
tries: MAX_FORBIDDEN_RETRIES,
|
|
482
|
-
base_interval: sleep_base_interval,
|
|
483
|
-
multiplier: 1.0,
|
|
484
|
-
rand_factor: 0.0,
|
|
485
|
-
on_retry: retry_callback
|
|
486
|
-
}
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
def sleep_base_interval
|
|
490
|
-
1.0
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
def retry_callback
|
|
494
|
-
proc do |exception, try, elapsed_time, next_interval|
|
|
495
|
-
Helper.log.warn("RETRY - #{exception.class}: '#{exception.message}'")
|
|
496
|
-
Helper.log.warn("#{try} tries in #{elapsed_time} seconds and #{next_interval} seconds until the next try")
|
|
497
|
-
Helper.log.warn GH_RATE_LIMIT_EXCEEDED_MSG
|
|
498
|
-
Helper.log.warn(client.rate_limit)
|
|
499
|
-
end
|
|
500
|
-
end
|
|
501
|
-
|
|
502
504
|
# @param [Object] msg
|
|
503
505
|
def sys_abort(msg)
|
|
504
506
|
abort(msg)
|
|
@@ -528,7 +530,7 @@ Make sure, that you push tags to remote repo via 'git push --tags'"
|
|
|
528
530
|
env_var
|
|
529
531
|
end
|
|
530
532
|
|
|
531
|
-
# @return [String] helper to return
|
|
533
|
+
# @return [String] helper to return GitHub "user/project"
|
|
532
534
|
def user_project
|
|
533
535
|
"#{@options[:user]}/#{@options[:project]}"
|
|
534
536
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "delegate"
|
|
4
|
-
|
|
4
|
+
require_relative "helper"
|
|
5
5
|
|
|
6
6
|
module GitHubChangelogGenerator
|
|
7
7
|
# This class wraps Options, and knows a list of known options. Others options
|
|
@@ -145,7 +145,17 @@ module GitHubChangelogGenerator
|
|
|
145
145
|
#
|
|
146
146
|
# @return [Hash] The GitHub `:token` key is censored in the output.
|
|
147
147
|
def censored_values
|
|
148
|
-
values.clone.tap { |opts| opts[:token] = opts[:token]
|
|
148
|
+
values.clone.tap { |opts| opts[:token] = censored_token(opts[:token]) }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def censored_token(opts_token)
|
|
152
|
+
if !opts_token.nil?
|
|
153
|
+
"Used token from options"
|
|
154
|
+
elsif ENV["CHANGELOG_GITHUB_TOKEN"]
|
|
155
|
+
"Used token from environment variable"
|
|
156
|
+
else
|
|
157
|
+
"No token used"
|
|
158
|
+
end
|
|
149
159
|
end
|
|
150
160
|
|
|
151
161
|
def unsupported_options
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
require_relative "helper"
|
|
4
|
+
require_relative "argv_parser"
|
|
5
|
+
require_relative "parser_file"
|
|
6
|
+
require_relative "file_parser_chooser"
|
|
7
7
|
|
|
8
8
|
module GitHubChangelogGenerator
|
|
9
9
|
class Parser
|
|
@@ -1,32 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "pathname"
|
|
4
|
-
|
|
5
3
|
module GitHubChangelogGenerator
|
|
6
4
|
ParserError = Class.new(StandardError)
|
|
7
5
|
|
|
8
|
-
class FileParserChooser
|
|
9
|
-
def initialize(options)
|
|
10
|
-
@options = options
|
|
11
|
-
@config_file = Pathname.new(options[:config_file])
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def parse!(_argv)
|
|
15
|
-
return nil unless (path = resolve_path)
|
|
16
|
-
|
|
17
|
-
ParserFile.new(@options, File.open(path)).parse!
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def resolve_path
|
|
21
|
-
return @config_file if @config_file.exist?
|
|
22
|
-
|
|
23
|
-
path = @config_file.expand_path
|
|
24
|
-
return path if File.exist?(path)
|
|
25
|
-
|
|
26
|
-
nil
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
6
|
# ParserFile is a configuration file reader which sets options in the
|
|
31
7
|
# given Hash.
|
|
32
8
|
#
|
|
@@ -29,7 +29,7 @@ module GitHubChangelogGenerator
|
|
|
29
29
|
defaults = {
|
|
30
30
|
heading_level: "##",
|
|
31
31
|
heading_structures: [
|
|
32
|
-
/^## \[(?<version>.+?)\]\((?<url>.+?)\)( \((?<date>.+?)\))?$/, # rubocop:disable Lint/MixedRegexpCaptureTypes
|
|
32
|
+
/^## \[(?<version>.+?)\](\((?<url>.+?)\))?( \((?<date>.+?)\))?$/, # rubocop:disable Lint/MixedRegexpCaptureTypes
|
|
33
33
|
/^## (?<version>.+?)( \((?<date>.+?)\))?$/ # rubocop:disable Lint/MixedRegexpCaptureTypes
|
|
34
34
|
]
|
|
35
35
|
}
|
|
@@ -45,6 +45,8 @@ module GitHubChangelogGenerator
|
|
|
45
45
|
# The following heading structures are currently valid:
|
|
46
46
|
# - ## [v1.0.2](https://github.com/zanui/chef-thumbor/tree/v1.0.1) (2015-03-24)
|
|
47
47
|
# - ## [v1.0.2](https://github.com/zanui/chef-thumbor/tree/v1.0.1)
|
|
48
|
+
# - ## [v1.0.2] (2015-03-24)
|
|
49
|
+
# - ## [v1.0.2]
|
|
48
50
|
# - ## v1.0.2 (2015-03-24)
|
|
49
51
|
# - ## v1.0.2
|
|
50
52
|
#
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
##
|
|
2
2
|
## Bundle of CA Root Certificates
|
|
3
3
|
##
|
|
4
|
-
## Certificate data from Mozilla as of: Tue
|
|
4
|
+
## Certificate data from Mozilla as of: Tue May 25 03:12:05 2021 GMT
|
|
5
5
|
##
|
|
6
6
|
## This is a bundle of X.509 certificates of public Certificate Authorities
|
|
7
7
|
## (CA). These were automatically extracted from Mozilla's root certificates
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
## Just configure this file as the SSLCACertificateFile.
|
|
15
15
|
##
|
|
16
16
|
## Conversion done with mk-ca-bundle.pl version 1.28.
|
|
17
|
-
## SHA256:
|
|
17
|
+
## SHA256: e292bd4e2d500c86df45b830d89417be5c42ee670408f1d2c454c63d8a782865
|
|
18
18
|
##
|
|
19
19
|
|
|
20
20
|
|
|
@@ -893,82 +893,6 @@ Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z
|
|
|
893
893
|
WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
|
|
894
894
|
-----END CERTIFICATE-----
|
|
895
895
|
|
|
896
|
-
Chambers of Commerce Root - 2008
|
|
897
|
-
================================
|
|
898
|
-
-----BEGIN CERTIFICATE-----
|
|
899
|
-
MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD
|
|
900
|
-
MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
|
|
901
|
-
bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
|
|
902
|
-
QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy
|
|
903
|
-
Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl
|
|
904
|
-
ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF
|
|
905
|
-
EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl
|
|
906
|
-
cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
|
|
907
|
-
AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA
|
|
908
|
-
XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj
|
|
909
|
-
h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/
|
|
910
|
-
ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk
|
|
911
|
-
NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g
|
|
912
|
-
D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331
|
|
913
|
-
lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ
|
|
914
|
-
0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
|
|
915
|
-
ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2
|
|
916
|
-
EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI
|
|
917
|
-
G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ
|
|
918
|
-
BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh
|
|
919
|
-
bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh
|
|
920
|
-
bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC
|
|
921
|
-
CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH
|
|
922
|
-
AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1
|
|
923
|
-
wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH
|
|
924
|
-
3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU
|
|
925
|
-
RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6
|
|
926
|
-
M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1
|
|
927
|
-
YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF
|
|
928
|
-
9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK
|
|
929
|
-
zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG
|
|
930
|
-
nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
|
|
931
|
-
OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ
|
|
932
|
-
-----END CERTIFICATE-----
|
|
933
|
-
|
|
934
|
-
Global Chambersign Root - 2008
|
|
935
|
-
==============================
|
|
936
|
-
-----BEGIN CERTIFICATE-----
|
|
937
|
-
MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD
|
|
938
|
-
MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv
|
|
939
|
-
bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu
|
|
940
|
-
QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx
|
|
941
|
-
NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg
|
|
942
|
-
Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ
|
|
943
|
-
QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
|
|
944
|
-
aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf
|
|
945
|
-
VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf
|
|
946
|
-
XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0
|
|
947
|
-
ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB
|
|
948
|
-
/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA
|
|
949
|
-
TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M
|
|
950
|
-
H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe
|
|
951
|
-
Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF
|
|
952
|
-
HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
|
|
953
|
-
wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB
|
|
954
|
-
AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT
|
|
955
|
-
BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE
|
|
956
|
-
BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm
|
|
957
|
-
aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm
|
|
958
|
-
aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp
|
|
959
|
-
1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0
|
|
960
|
-
dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG
|
|
961
|
-
/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6
|
|
962
|
-
ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s
|
|
963
|
-
dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg
|
|
964
|
-
9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH
|
|
965
|
-
foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du
|
|
966
|
-
qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr
|
|
967
|
-
P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq
|
|
968
|
-
c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
|
|
969
|
-
09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
|
|
970
|
-
-----END CERTIFICATE-----
|
|
971
|
-
|
|
972
896
|
Go Daddy Root Certificate Authority - G2
|
|
973
897
|
========================================
|
|
974
898
|
-----BEGIN CERTIFICATE-----
|
|
@@ -58,10 +58,10 @@ module GitHubChangelogGenerator
|
|
|
58
58
|
|
|
59
59
|
log = generator.compound_changelog
|
|
60
60
|
|
|
61
|
-
output_filename =
|
|
61
|
+
output_filename = options[:output].to_s
|
|
62
62
|
File.open(output_filename, "w") { |file| file.write(log) }
|
|
63
63
|
puts "Done!"
|
|
64
|
-
puts "Generated log placed in #{
|
|
64
|
+
puts "Generated log placed in #{File.absolute_path(output_filename)}"
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
require "octokit"
|
|
@@ -7,16 +6,15 @@ require "logger"
|
|
|
7
6
|
require "active_support"
|
|
8
7
|
require "active_support/core_ext/object/blank"
|
|
9
8
|
require "json"
|
|
10
|
-
require "multi_json"
|
|
11
9
|
require "benchmark"
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
require_relative "github_changelog_generator/helper"
|
|
12
|
+
require_relative "github_changelog_generator/options"
|
|
13
|
+
require_relative "github_changelog_generator/parser"
|
|
14
|
+
require_relative "github_changelog_generator/parser_file"
|
|
15
|
+
require_relative "github_changelog_generator/generator/generator"
|
|
16
|
+
require_relative "github_changelog_generator/version"
|
|
17
|
+
require_relative "github_changelog_generator/reader"
|
|
20
18
|
|
|
21
19
|
# The main module, where placed all classes (now, at least)
|
|
22
20
|
module GitHubChangelogGenerator
|
|
@@ -24,24 +22,28 @@ module GitHubChangelogGenerator
|
|
|
24
22
|
class ChangelogGenerator
|
|
25
23
|
# Class, responsible for whole changelog generation cycle
|
|
26
24
|
# @return initialised instance of ChangelogGenerator
|
|
27
|
-
def initialize
|
|
28
|
-
@options = Parser.parse_options
|
|
29
|
-
@generator = Generator.new
|
|
25
|
+
def initialize(params = ARGV)
|
|
26
|
+
@options = Parser.parse_options(params)
|
|
27
|
+
@generator = Generator.new(@options)
|
|
30
28
|
end
|
|
31
29
|
|
|
32
30
|
# The entry point of this script to generate changelog
|
|
33
31
|
# @raise (ChangelogGeneratorError) Is thrown when one of specified tags was not found in list of tags.
|
|
34
32
|
def run
|
|
35
|
-
log =
|
|
33
|
+
log = generator.compound_changelog
|
|
36
34
|
|
|
37
|
-
if
|
|
38
|
-
output_filename =
|
|
35
|
+
if options.write_to_file?
|
|
36
|
+
output_filename = options[:output].to_s
|
|
39
37
|
File.open(output_filename, "wb") { |file| file.write(log) }
|
|
40
38
|
puts "Done!"
|
|
41
|
-
puts "Generated log placed in #{
|
|
39
|
+
puts "Generated log placed in #{File.absolute_path(output_filename)}"
|
|
42
40
|
else
|
|
43
41
|
puts log
|
|
44
42
|
end
|
|
45
43
|
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
attr_reader :generator, :options
|
|
46
48
|
end
|
|
47
49
|
end
|
|
@@ -206,11 +206,11 @@
|
|
|
206
206
|
|
|
207
207
|
<p> --github-site URL</p>
|
|
208
208
|
|
|
209
|
-
<p> The Enterprise
|
|
209
|
+
<p> The Enterprise GitHub site on which your project is hosted.</p>
|
|
210
210
|
|
|
211
211
|
<p> --github-api URL</p>
|
|
212
212
|
|
|
213
|
-
<p> The enterprise endpoint to use for your
|
|
213
|
+
<p> The enterprise endpoint to use for your GitHub API.</p>
|
|
214
214
|
|
|
215
215
|
<p> --simple-list</p>
|
|
216
216
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe GitHubChangelogGenerator::ChangelogGenerator do
|
|
4
|
+
describe "#run" do
|
|
5
|
+
let(:arguments) { [] }
|
|
6
|
+
let(:instance) { described_class.new(arguments) }
|
|
7
|
+
let(:output_path) { File.join(__dir__, "tmp", "test.output") }
|
|
8
|
+
|
|
9
|
+
after { FileUtils.rm_rf(output_path) }
|
|
10
|
+
|
|
11
|
+
let(:generator) { instance_double(::GitHubChangelogGenerator::Generator) }
|
|
12
|
+
|
|
13
|
+
before do
|
|
14
|
+
allow(instance).to receive(:generator) { generator }
|
|
15
|
+
allow(generator).to receive(:compound_changelog) { "content" }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context "when full path given as the --output argument" do
|
|
19
|
+
let(:arguments) { ["--output", output_path] }
|
|
20
|
+
it "puts the complete output path to STDOUT" do
|
|
21
|
+
expect { instance.run }.to output(Regexp.new(output_path)).to_stdout
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context "when empty value given as the --output argument" do
|
|
26
|
+
let(:arguments) { ["--output", ""] }
|
|
27
|
+
it "puts the complete output path to STDOUT" do
|
|
28
|
+
expect { instance.run }.to output(/content/).to_stdout
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -120,7 +120,7 @@ module GitHubChangelogGenerator
|
|
|
120
120
|
|
|
121
121
|
let(:pull_requests) do
|
|
122
122
|
[
|
|
123
|
-
pr("no labels", [], "",
|
|
123
|
+
pr("no labels", [], "", "20", "login" => "user1"),
|
|
124
124
|
pr("breaking", ["breaking"], "", "23", "login" => "user5"),
|
|
125
125
|
pr("enhancement", ["enhancement"], "", "21", "login" => "user5"),
|
|
126
126
|
pr("bug", ["bug"], "", "22", "login" => "user5"),
|
|
@@ -129,7 +129,7 @@ module GitHubChangelogGenerator
|
|
|
129
129
|
pr("security", ["security"], "", "30", "login" => "user5"),
|
|
130
130
|
pr("all the labels", %w[breaking enhancement bug deprecated removed security], "", "24", "login" => "user5"),
|
|
131
131
|
pr("all the labels different order", %w[bug breaking enhancement security remove deprecated], "", "25", "login" => "user5"),
|
|
132
|
-
pr("some unmapped labels", %w[tests-fail bug], "",
|
|
132
|
+
pr("some unmapped labels", %w[tests-fail bug], "", "26", "login" => "user5"),
|
|
133
133
|
pr("no mapped labels", %w[docs maintenance], "", "27", "login" => "user5")
|
|
134
134
|
]
|
|
135
135
|
end
|
|
@@ -137,6 +137,67 @@ module GitHubChangelogGenerator
|
|
|
137
137
|
it { is_expected.to eq(expected_issues) }
|
|
138
138
|
end
|
|
139
139
|
end
|
|
140
|
+
|
|
141
|
+
describe "#find_issues_to_add" do
|
|
142
|
+
let(:issues) { [issue] }
|
|
143
|
+
let(:tag_name) { nil }
|
|
144
|
+
let(:filtered_tags) { [] }
|
|
145
|
+
before { generator.instance_variable_set(:@filtered_tags, filtered_tags) }
|
|
146
|
+
|
|
147
|
+
subject { generator.find_issues_to_add(issues, tag_name) }
|
|
148
|
+
|
|
149
|
+
context "issue without milestone" do
|
|
150
|
+
let(:issue) { { "labels" => [] } }
|
|
151
|
+
|
|
152
|
+
it { is_expected.to be_empty }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
context "milestone title not in the filtered tags" do
|
|
156
|
+
let(:issue) { { "milestone" => { "title" => "a title" } } }
|
|
157
|
+
let(:filtered_tags) { [{ "name" => "another name" }] }
|
|
158
|
+
|
|
159
|
+
it { is_expected.to be_empty }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context "milestone title matches the tag name" do
|
|
163
|
+
let(:tag_name) { "tag name" }
|
|
164
|
+
let(:issue) { { "milestone" => { "title" => tag_name } } }
|
|
165
|
+
let(:filtered_tags) { [{ "name" => tag_name }] }
|
|
166
|
+
|
|
167
|
+
it { is_expected.to contain_exactly(issue) }
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
describe "#remove_issues_in_milestones" do
|
|
172
|
+
let(:issues) { [issue] }
|
|
173
|
+
|
|
174
|
+
context "issue without milestone" do
|
|
175
|
+
let(:issue) { { "labels" => [] } }
|
|
176
|
+
|
|
177
|
+
it "is not filtered" do
|
|
178
|
+
expect { generator.remove_issues_in_milestones(issues) }.to_not(change { issues })
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
context "remove issues of open milestones if option is set" do
|
|
183
|
+
let(:issue) { { "milestone" => { "state" => "open" } } }
|
|
184
|
+
let(:options) { { issues_of_open_milestones: false } }
|
|
185
|
+
|
|
186
|
+
it "is filtered" do
|
|
187
|
+
expect { generator.remove_issues_in_milestones(issues) }.to change { issues }.to([])
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
context "milestone in the tag list" do
|
|
192
|
+
let(:milestone_name) { "milestone name" }
|
|
193
|
+
let(:issue) { { "milestone" => { "title" => milestone_name } } }
|
|
194
|
+
|
|
195
|
+
it "is filtered" do
|
|
196
|
+
generator.instance_variable_set(:@filtered_tags, [{ "name" => milestone_name }])
|
|
197
|
+
expect { generator.remove_issues_in_milestones(issues) }.to change { issues }.to([])
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
140
201
|
end
|
|
141
202
|
end
|
|
142
203
|
end
|