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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +52 -16
  3. data/bin/github_changelog_generator +1 -1
  4. data/lib/github_changelog_generator/argv_parser.rb +2 -2
  5. data/lib/github_changelog_generator/file_parser_chooser.rb +27 -0
  6. data/lib/github_changelog_generator/generator/entry.rb +3 -3
  7. data/lib/github_changelog_generator/generator/generator.rb +15 -10
  8. data/lib/github_changelog_generator/generator/generator_fetcher.rb +22 -24
  9. data/lib/github_changelog_generator/generator/generator_processor.rb +14 -24
  10. data/lib/github_changelog_generator/generator/generator_tags.rb +24 -34
  11. data/lib/github_changelog_generator/generator/section.rb +9 -4
  12. data/lib/github_changelog_generator/octo_fetcher.rb +38 -36
  13. data/lib/github_changelog_generator/options.rb +12 -2
  14. data/lib/github_changelog_generator/parser.rb +4 -4
  15. data/lib/github_changelog_generator/parser_file.rb +0 -24
  16. data/lib/github_changelog_generator/reader.rb +3 -1
  17. data/lib/github_changelog_generator/ssl_certs/cacert.pem +2 -78
  18. data/lib/github_changelog_generator/task.rb +2 -2
  19. data/lib/github_changelog_generator/version.rb +1 -1
  20. data/lib/github_changelog_generator.rb +18 -16
  21. data/man/git-generate-changelog.html +2 -2
  22. data/spec/github_changelog_generator_spec.rb +32 -0
  23. data/spec/unit/generator/entry_spec.rb +2 -2
  24. data/spec/unit/generator/generator_processor_spec.rb +61 -0
  25. data/spec/unit/generator/generator_spec.rb +151 -0
  26. data/spec/unit/generator/generator_tags_spec.rb +1 -1
  27. data/spec/unit/generator/section_spec.rb +9 -0
  28. data/spec/unit/octo_fetcher_spec.rb +8 -11
  29. data/spec/unit/{parse_file_spec.rb → parser_file_spec.rb} +35 -15
  30. data/spec/unit/reader_spec.rb +9 -0
  31. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits/when_API_is_valid/returns_commits.json +1 -1
  32. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits_before/when_API_is_valid/returns_commits.json +1 -1
  33. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issue_with_proper_key/values.json +1 -1
  34. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues.json +1 -1
  35. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues_with_labels.json +1 -1
  36. 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
  37. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_pull_requests_with_labels.json +1 -1
  38. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid.json +1 -1
  39. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_correct_pull_request_keys.json +1 -1
  40. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_pull_requests.json +1 -1
  41. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid.json +1 -1
  42. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid/returns_commit.json +1 -1
  43. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid.json +1 -1
  44. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid/returns_date.json +1 -1
  45. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid.json +1 -1
  46. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid/populates_issues.json +1 -1
  47. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid.json +1 -1
  48. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags.json +1 -1
  49. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags_count.json +1 -1
  50. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid.json +1 -1
  51. 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 :async_http
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 get_all_tags
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 ||= client.branches(user_project).map { |branch| [branch[:name], branch] }.to_h
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(&block)
460
- Retriable.retriable(retry_options, &block)
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 Github "user/project"
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
- require "github_changelog_generator/helper"
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].nil? ? "No token used" : "hidden value" }
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
- require "github_changelog_generator/helper"
5
- require "github_changelog_generator/argv_parser"
6
- require "github_changelog_generator/parser_file"
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 Apr 13 03:12:04 2021 GMT
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: f377673fa3c22ba2188a4cea041c7b8c99a4817ffde6821e98325ce89324e5aa
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 = (options[:output]).to_s
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 #{Dir.pwd}/#{output_filename}"
64
+ puts "Generated log placed in #{File.absolute_path(output_filename)}"
65
65
  end
66
66
  end
67
67
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GitHubChangelogGenerator
4
- VERSION = "1.16.3"
4
+ VERSION = "1.17.0"
5
5
  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
- require "github_changelog_generator/helper"
14
- require "github_changelog_generator/options"
15
- require "github_changelog_generator/parser"
16
- require "github_changelog_generator/parser_file"
17
- require "github_changelog_generator/generator/generator"
18
- require "github_changelog_generator/version"
19
- require "github_changelog_generator/reader"
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 @options
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 = @generator.compound_changelog
33
+ log = generator.compound_changelog
36
34
 
37
- if @options.write_to_file?
38
- output_filename = @options[:output].to_s
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 #{Dir.pwd}/#{output_filename}"
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 Github site on which your project is hosted.</p>
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 Github API.</p>
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", [], "", "20", "login" => "user1"),
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], "", "26", "login" => "user5"),
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