github_changelog_generator 1.15.0.pre.alpha → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +1 -1
  3. data/README.md +332 -275
  4. data/Rakefile +3 -4
  5. data/bin/git-generate-changelog +1 -1
  6. data/lib/github_changelog_generator.rb +10 -6
  7. data/lib/github_changelog_generator/generator/entry.rb +218 -0
  8. data/lib/github_changelog_generator/generator/generator.rb +126 -104
  9. data/lib/github_changelog_generator/generator/generator_fetcher.rb +139 -23
  10. data/lib/github_changelog_generator/generator/generator_processor.rb +59 -27
  11. data/lib/github_changelog_generator/generator/generator_tags.rb +26 -22
  12. data/lib/github_changelog_generator/generator/section.rb +124 -0
  13. data/lib/github_changelog_generator/helper.rb +1 -1
  14. data/lib/github_changelog_generator/octo_fetcher.rb +261 -130
  15. data/lib/github_changelog_generator/options.rb +74 -1
  16. data/lib/github_changelog_generator/parser.rb +120 -176
  17. data/lib/github_changelog_generator/parser_file.rb +8 -3
  18. data/lib/github_changelog_generator/reader.rb +2 -2
  19. data/lib/github_changelog_generator/task.rb +5 -6
  20. data/lib/github_changelog_generator/version.rb +1 -1
  21. data/man/git-generate-changelog.1 +144 -45
  22. data/man/git-generate-changelog.1.html +157 -84
  23. data/man/git-generate-changelog.html +19 -7
  24. data/man/git-generate-changelog.md +151 -84
  25. data/spec/files/github-changelog-generator.md +114 -114
  26. data/spec/{install-gem-in-bundler.gemfile → install_gem_in_bundler.gemfile} +2 -0
  27. data/spec/spec_helper.rb +2 -6
  28. data/spec/unit/generator/entry_spec.rb +766 -0
  29. data/spec/unit/generator/generator_processor_spec.rb +103 -41
  30. data/spec/unit/generator/generator_spec.rb +47 -0
  31. data/spec/unit/generator/generator_tags_spec.rb +56 -24
  32. data/spec/unit/generator/section_spec.rb +34 -0
  33. data/spec/unit/octo_fetcher_spec.rb +247 -197
  34. data/spec/unit/options_spec.rb +28 -4
  35. data/spec/unit/parse_file_spec.rb +2 -2
  36. data/spec/unit/parser_spec.rb +0 -79
  37. data/spec/unit/reader_spec.rb +4 -4
  38. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits/when_API_is_valid/returns_commits.json +1 -0
  39. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits_before/when_API_is_valid/returns_commits.json +1 -1
  40. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid.json +1 -1
  41. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issue_with_proper_key/values.json +1 -1
  42. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues.json +1 -1
  43. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues_with_labels.json +1 -1
  44. 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
  45. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_pull_requests_with_labels.json +1 -1
  46. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid.json +1 -1
  47. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_correct_pull_request_keys.json +1 -1
  48. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_pull_requests.json +1 -1
  49. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid.json +1 -1
  50. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid/returns_commit.json +1 -1
  51. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid.json +1 -1
  52. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid/returns_date.json +1 -1
  53. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid.json +1 -1
  54. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid/populates_issues.json +1 -1
  55. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid.json +1 -1
  56. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags.json +1 -1
  57. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags_count.json +1 -1
  58. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_wrong_token_provided.json +1 -1
  59. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_wrong_token_provided/should_raise_Unauthorized_error.json +1 -1
  60. metadata +71 -38
  61. data/bin/ghclgen +0 -5
  62. data/lib/github_changelog_generator/generator/generator_generation.rb +0 -180
  63. data/spec/unit/generator/generator_generation_spec.rb +0 -17
@@ -2,78 +2,140 @@
2
2
 
3
3
  module GitHubChangelogGenerator
4
4
  describe Generator do
5
- let(:default_options) { GitHubChangelogGenerator::Parser.default_options }
5
+ let(:default_options) { GitHubChangelogGenerator::Parser.default_options.merge(verbose: false) }
6
6
  let(:options) { {} }
7
7
  let(:generator) { described_class.new(default_options.merge(options)) }
8
-
9
8
  let(:bad_label) { { "name" => "BAD" } }
10
- let(:bad_issue) { { "labels" => [bad_label] } }
11
9
  let(:good_label) { { "name" => "GOOD" } }
12
- let(:good_issue) { { "labels" => [good_label] } }
13
- let(:unlabeled_issue) { { "labels" => [] } }
14
- let(:issues) { [bad_issue, good_issue, unlabeled_issue] }
15
10
 
16
- describe "#exclude_issues_by_labels" do
17
- subject do
18
- generator.exclude_issues_by_labels(issues)
19
- end
11
+ describe "pull requests" do
12
+ let(:bad_pull_request) { { "pull_request" => {}, "labels" => [bad_label] } }
13
+ let(:good_pull_request) { { "pull_request" => {}, "labels" => [good_label] } }
14
+ let(:unlabeled_pull_request) { { "pull_request" => {}, "labels" => [] } }
15
+ let(:pull_requests) { [bad_pull_request, good_pull_request, unlabeled_pull_request] }
20
16
 
21
- let(:expected_issues) { issues }
17
+ describe "#filter_wo_labels" do
18
+ subject do
19
+ generator.filter_wo_labels(pull_requests)
20
+ end
22
21
 
23
- it { is_expected.to eq(expected_issues) }
22
+ let(:expected_pull_requests) { pull_requests }
24
23
 
25
- context "when 'exclude_lables' is provided" do
26
- let(:options) { { exclude_labels: %w[BAD BOO] } }
27
- let(:expected_issues) { [good_issue, unlabeled_issue] }
24
+ it { is_expected.to eq(expected_pull_requests) }
28
25
 
29
- it { is_expected.to eq(expected_issues) }
30
- end
26
+ context "when 'add_pr_wo_labels' is false" do
27
+ let(:options) { { add_pr_wo_labels: false } }
28
+ let(:expected_pull_requests) { [bad_pull_request, good_pull_request] }
31
29
 
32
- context "with no option given" do
33
- subject(:generator) { described_class.new }
34
- it "passes everything through when no option given" do
35
- result = generator.exclude_issues_by_labels(issues)
30
+ it { is_expected.to eq(expected_pull_requests) }
31
+ end
36
32
 
37
- expect(result).to eq(issues)
33
+ context "when 'add_pr_wo_labels' is true" do
34
+ let(:options) { { add_pr_wo_labels: true } }
35
+
36
+ it { is_expected.to eq(expected_pull_requests) }
38
37
  end
39
38
  end
40
39
  end
41
40
 
42
- describe "#get_filtered_issues" do
43
- subject do
44
- generator.get_filtered_issues(issues)
45
- end
46
-
47
- let(:expected_issues) { issues }
41
+ describe "issues" do
42
+ let(:bad_issue) { { "labels" => [bad_label] } }
43
+ let(:good_issue) { { "labels" => [good_label] } }
44
+ let(:unlabeled_issue) { { "labels" => [] } }
45
+ let(:issues) { [bad_issue, good_issue, unlabeled_issue] }
48
46
 
49
- it { is_expected.to eq(expected_issues) }
47
+ describe "#filter_wo_labels" do
48
+ subject do
49
+ generator.filter_wo_labels(issues)
50
+ end
50
51
 
51
- context "when 'exclude_labels' is provided" do
52
- let(:options) { { exclude_labels: %w[BAD BOO] } }
53
- let(:expected_issues) { [good_issue, unlabeled_issue] }
52
+ let(:expected_issues) { issues }
54
53
 
55
54
  it { is_expected.to eq(expected_issues) }
55
+
56
+ context "when 'add_issues_wo_labels' is false" do
57
+ let(:options) { { add_issues_wo_labels: false } }
58
+ let(:expected_issues) { [bad_issue, good_issue] }
59
+
60
+ it { is_expected.to eq(expected_issues) }
61
+ end
62
+
63
+ context "when 'add_issues_wo_labels' is true" do
64
+ let(:options) { { add_issues_wo_labels: true } }
65
+
66
+ it { is_expected.to eq(expected_issues) }
67
+ end
56
68
  end
57
69
 
58
- context "when 'add_issues_wo_labels' is false" do
59
- let(:options) { { add_issues_wo_labels: false } }
60
- let(:expected_issues) { [bad_issue, good_issue] }
70
+ describe "#exclude_issues_by_labels" do
71
+ subject do
72
+ generator.exclude_issues_by_labels(issues)
73
+ end
74
+
75
+ let(:expected_issues) { issues }
61
76
 
62
77
  it { is_expected.to eq(expected_issues) }
63
78
 
64
- context "with 'exclude_labels'" do
65
- let(:options) { { add_issues_wo_labels: false, exclude_labels: %w[GOOD] } }
66
- let(:expected_issues) { [bad_issue] }
79
+ context "when 'exclude_labels' is provided" do
80
+ let(:options) { { exclude_labels: %w[BAD BOO] } }
81
+ let(:expected_issues) { [good_issue, unlabeled_issue] }
67
82
 
68
83
  it { is_expected.to eq(expected_issues) }
69
84
  end
85
+
86
+ context "with no option given" do
87
+ subject(:generator) { described_class.new }
88
+ it "passes everything through when no option given" do
89
+ result = generator.exclude_issues_by_labels(issues)
90
+
91
+ expect(result).to eq(issues)
92
+ end
93
+ end
70
94
  end
71
95
 
72
- context "when 'include_labels' is specified" do
73
- let(:options) { { include_labels: %w[GOOD] } }
74
- let(:expected_issues) { [good_issue] }
96
+ describe "#get_filtered_issues" do
97
+ subject do
98
+ generator.get_filtered_issues(issues)
99
+ end
100
+
101
+ let(:expected_issues) { issues }
75
102
 
76
103
  it { is_expected.to eq(expected_issues) }
104
+
105
+ context "when 'exclude_labels' is provided" do
106
+ let(:options) { { exclude_labels: %w[BAD BOO] } }
107
+ let(:expected_issues) { [good_issue, unlabeled_issue] }
108
+
109
+ it { is_expected.to eq(expected_issues) }
110
+ end
111
+
112
+ context "when 'add_issues_wo_labels' is false" do
113
+ let(:options) { { add_issues_wo_labels: false } }
114
+ let(:expected_issues) { [bad_issue, good_issue] }
115
+
116
+ it { is_expected.to eq(expected_issues) }
117
+
118
+ context "with 'exclude_labels'" do
119
+ let(:options) { { add_issues_wo_labels: false, exclude_labels: %w[GOOD] } }
120
+ let(:expected_issues) { [bad_issue] }
121
+
122
+ it { is_expected.to eq(expected_issues) }
123
+ end
124
+
125
+ context "with 'include_labels'" do
126
+ let(:options) { { add_issues_wo_labels: false, include_labels: %w[GOOD] } }
127
+ let(:expected_issues) { [good_issue] }
128
+
129
+ it { is_expected.to eq(expected_issues) }
130
+ end
131
+ end
132
+
133
+ context "when 'include_labels' is specified" do
134
+ let(:options) { { include_labels: %w[GOOD] } }
135
+ let(:expected_issues) { [good_issue, unlabeled_issue] }
136
+
137
+ it { is_expected.to eq(expected_issues) }
138
+ end
77
139
  end
78
140
  end
79
141
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "github_changelog_generator/generator/generator"
4
+
5
+ RSpec.describe GitHubChangelogGenerator::Generator do
6
+ let(:header) { "# Changelog" }
7
+ let(:generator) { described_class.new({ header: header }) }
8
+ let(:content) do
9
+ <<~'BASE'
10
+ ## [1.3.10](https://github.com/xxx/yyy/tree/1.3.10) (2015-03-18)
11
+
12
+ [Full Changelog](https://github.com/xxx/yyy/compare/1.3.9...1.3.10)
13
+
14
+ **Fixed bugs:**
15
+
16
+
17
+ BASE
18
+ end
19
+ let(:footer) do
20
+ <<~CREDIT
21
+ \\* *This Changelog was automatically generated \
22
+ by [github_changelog_generator]\
23
+ (https://github.com/github-changelog-generator/github-changelog-generator)*
24
+ CREDIT
25
+ end
26
+
27
+ context "when the given base file has previously appended template messages" do
28
+ describe "#remove_old_fixed_string" do
29
+ it "removes old template headers and footers" do
30
+ log = +"#{header}\n\n#{header}\n#{header}#{content}\n\n#{footer}\n#{footer}#{footer}"
31
+
32
+ expect(generator.send(:remove_old_fixed_string, log)).to eq content
33
+ end
34
+ end
35
+ end
36
+
37
+ context "when plain contents string was given" do
38
+ describe "#insert_fixed_string" do
39
+ it "append template messages at header and footer" do
40
+ log = String.new(content)
41
+ ans = "#{header}\n\n#{content}\n\n#{footer}"
42
+
43
+ expect(generator.send(:insert_fixed_string, log)).to eq ans
44
+ end
45
+ end
46
+ end
47
+ end
@@ -13,11 +13,38 @@ describe GitHubChangelogGenerator::Generator do
13
13
  end
14
14
  end
15
15
 
16
+ describe "#detect_link_tag_time" do
17
+ let(:newer_tag) { nil }
18
+
19
+ let(:default_options) { GitHubChangelogGenerator::Parser.default_options.merge(verbose: false) }
20
+ let(:options) do
21
+ {
22
+ future_release: "2.0.0"
23
+ }
24
+ end
25
+ let(:generator) { described_class.new(default_options.merge(options)) }
26
+
27
+ subject do
28
+ generator.detect_link_tag_time(newer_tag)
29
+ end
30
+
31
+ context "When the local date is not the same as the UTC date" do
32
+ before do
33
+ # 2020-12-27T17:00:00-10:00 is 2020-12-28T03:00:00Z.
34
+ # GitHub API date & time use UTC, so this instant when converted as a
35
+ # date should be 2020-12-28.
36
+ expect(Time).to receive(:new).and_return(Time.new(2020, 12, 27, 17, 0, 0, "-10:00"))
37
+ end
38
+
39
+ it { is_expected.to eq(["2.0.0", "2.0.0", Time.gm(2020, 12, 28, 3)]) }
40
+ end
41
+ end
42
+
16
43
  describe "#tag_section_mapping" do
17
44
  let(:all_tags) { tags_from_strings(%w[8 7 6 5 4 3 2 1]) }
18
45
  let(:sorted_tags) { all_tags }
19
46
 
20
- let(:default_options) { GitHubChangelogGenerator::Parser.default_options }
47
+ let(:default_options) { GitHubChangelogGenerator::Parser.default_options.merge(verbose: false) }
21
48
  let(:options) { {} }
22
49
  let(:generator) { described_class.new(default_options.merge(options)) }
23
50
 
@@ -57,10 +84,10 @@ describe GitHubChangelogGenerator::Generator do
57
84
  shared_examples_for "a changelog with some exclusions" do
58
85
  let(:expected_mapping) do
59
86
  {
60
- tag_with_name("8") => [tag_with_name("7"), tag_with_name("8")],
61
- tag_with_name("6") => [tag_with_name("5"), tag_with_name("6")],
87
+ tag_with_name("8") => [tag_with_name("6"), tag_with_name("8")],
88
+ tag_with_name("6") => [tag_with_name("4"), tag_with_name("6")],
62
89
  tag_with_name("4") => [tag_with_name("3"), tag_with_name("4")],
63
- tag_with_name("3") => [tag_with_name("2"), tag_with_name("3")],
90
+ tag_with_name("3") => [tag_with_name("1"), tag_with_name("3")],
64
91
  tag_with_name("1") => [nil, tag_with_name("1")]
65
92
  }
66
93
  end
@@ -130,6 +157,22 @@ describe GitHubChangelogGenerator::Generator do
130
157
  end
131
158
  end
132
159
 
160
+ describe "#filter_included_tags_regex" do
161
+ subject { generator.filter_included_tags(tags_from_strings(%w[1 2 3])) }
162
+
163
+ context "with matching regex" do
164
+ let(:generator) { GitHubChangelogGenerator::Generator.new(include_tags_regex: "[23]") }
165
+ it { is_expected.to be_a Array }
166
+ it { is_expected.to match_array(tags_from_strings(%w[2 3])) }
167
+ end
168
+
169
+ context "with non-matching regex" do
170
+ let(:generator) { GitHubChangelogGenerator::Generator.new(include_tags_regex: "[45]") }
171
+ it { is_expected.to be_a Array }
172
+ it { is_expected.to match_array(tags_from_strings(%w[])) }
173
+ end
174
+ end
175
+
133
176
  describe "#filter_excluded_tags" do
134
177
  subject { generator.filter_excluded_tags(tags_from_strings(%w[1 2 3])) }
135
178
 
@@ -182,28 +225,25 @@ describe GitHubChangelogGenerator::Generator do
182
225
  let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "2") }
183
226
  it { is_expected.to be_a Array }
184
227
  it { is_expected.to match_array(tags_from_strings(%w[1 2])) }
228
+
229
+ context "with since tag set to the most recent tag" do
230
+ let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "1") }
231
+ it { is_expected.to match_array(tags_from_strings(%w[1])) }
232
+ end
185
233
  end
186
234
 
187
235
  context "with invalid since tag" do
188
236
  let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "Invalid tag") }
189
- it { is_expected.to be_a Array }
190
- it { is_expected.to match_array(tags_from_strings(%w[1 2 3])) }
237
+ it { expect { subject }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError) }
191
238
  end
192
239
  end
193
240
 
194
241
  context "with empty array" do
195
242
  subject { generator.filter_since_tag(tags_from_strings(%w[])) }
196
243
 
197
- context "with valid since tag" do
198
- let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "2") }
199
- it { is_expected.to be_a Array }
200
- it { is_expected.to match_array(tags_from_strings(%w[])) }
201
- end
202
-
203
244
  context "with invalid since tag" do
204
245
  let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "Invalid tag") }
205
- it { is_expected.to be_a Array }
206
- it { is_expected.to match_array(tags_from_strings(%w[])) }
246
+ it { expect { subject }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError) }
207
247
  end
208
248
  end
209
249
  end
@@ -220,24 +260,16 @@ describe GitHubChangelogGenerator::Generator do
220
260
 
221
261
  context "with invalid due tag" do
222
262
  let(:generator) { GitHubChangelogGenerator::Generator.new(due_tag: "Invalid tag") }
223
- it { is_expected.to be_a Array }
224
- it { is_expected.to match_array(tags_from_strings(%w[1 2 3])) }
263
+ it { expect { subject }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError) }
225
264
  end
226
265
  end
227
266
 
228
267
  context "with empty array" do
229
268
  subject { generator.filter_due_tag(tags_from_strings(%w[])) }
230
269
 
231
- context "with valid due tag" do
232
- let(:generator) { GitHubChangelogGenerator::Generator.new(due_tag: "2") }
233
- it { is_expected.to be_a Array }
234
- it { is_expected.to match_array(tags_from_strings(%w[])) }
235
- end
236
-
237
270
  context "with invalid due tag" do
238
271
  let(:generator) { GitHubChangelogGenerator::Generator.new(due_tag: "Invalid tag") }
239
- it { is_expected.to be_a Array }
240
- it { is_expected.to match_array(tags_from_strings(%w[])) }
272
+ it { expect { subject }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError) }
241
273
  end
242
274
  end
243
275
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GitHubChangelogGenerator
4
+ RSpec.describe Section do
5
+ let(:options) { {} }
6
+ subject(:section) { described_class.new(options) }
7
+
8
+ describe "#encapsulate_string" do
9
+ let(:string) { "" }
10
+
11
+ context "with the empty string" do
12
+ it "returns the string" do
13
+ expect(section.send(:encapsulate_string, string)).to eq string
14
+ end
15
+ end
16
+
17
+ context "with a string with an escape-needing character in it" do
18
+ let(:string) { "<Inside> and outside" }
19
+
20
+ it "returns the string escaped" do
21
+ expect(section.send(:encapsulate_string, string)).to eq '\\<Inside\\> and outside'
22
+ end
23
+ end
24
+
25
+ context "with a backticked string with an escape-needing character in it" do
26
+ let(:string) { 'back `\` slash' }
27
+
28
+ it "returns the string" do
29
+ expect(section.send(:encapsulate_string, string)).to eq 'back `\` slash'
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -6,7 +6,7 @@ INVALID_TOKEN = "0000000000000000"
6
6
  describe GitHubChangelogGenerator::OctoFetcher do
7
7
  let(:options) do
8
8
  {
9
- user: "skywinder",
9
+ user: "github-changelog-generator",
10
10
  project: "changelog_test"
11
11
  }
12
12
  end
@@ -85,11 +85,54 @@ describe GitHubChangelogGenerator::OctoFetcher do
85
85
  end
86
86
  end
87
87
 
88
+ describe "#fetch_tag_shas" do
89
+ let(:commits) do
90
+ [
91
+ { sha: "0", parents: [{ sha: "1" }, { sha: "6" }] },
92
+ { sha: "1", parents: [{ sha: "2" }] },
93
+ { sha: "2", parents: [{ sha: "3" }] },
94
+ { sha: "3", parents: [{ sha: "4" }] },
95
+ { sha: "4", parents: [{ sha: "5" }] },
96
+ { sha: "5", parents: [] },
97
+ { sha: "6", parents: [{ sha: "7" }, { sha: "8" }] },
98
+ { sha: "7", parents: [{ sha: "9" }, { sha: "10" }] },
99
+ { sha: "8", parents: [{ sha: "11" }, { sha: "12" }] },
100
+ { sha: "9", parents: [] },
101
+ { sha: "10", parents: [] },
102
+ { sha: "11", parents: [] },
103
+ { sha: "12", parents: [] }
104
+ ]
105
+ end
106
+
107
+ let(:tag0) { { "name" => "tag-0", "commit" => { "sha" => "0" } } }
108
+ let(:tag1) { { "name" => "tag-1", "commit" => { "sha" => "1" } } }
109
+ let(:tag6) { { "name" => "tag-6", "commit" => { "sha" => "6" } } }
110
+
111
+ before do
112
+ allow(fetcher).to receive(:commits).and_return(commits)
113
+ end
114
+
115
+ it "should find all shas with single parents" do
116
+ fetcher.fetch_tag_shas([tag1])
117
+ expect(tag1["shas_in_tag"]).to eq(Set.new(%w[1 2 3 4 5]))
118
+ end
119
+
120
+ it "should find all shas with multiple parents" do
121
+ fetcher.fetch_tag_shas([tag6])
122
+ expect(tag6["shas_in_tag"]).to eq(Set.new(%w[6 7 8 9 10 11 12]))
123
+ end
124
+
125
+ it "should find all shas with mixed parents" do
126
+ fetcher.fetch_tag_shas([tag0])
127
+ expect(tag0["shas_in_tag"]).to eq(Set.new(%w[0 1 2 3 4 5 6 7 8 9 10 11 12]))
128
+ end
129
+ end
130
+
88
131
  describe "#github_fetch_tags" do
89
132
  context "when wrong token provided", :vcr do
90
133
  let(:options) do
91
134
  {
92
- user: "skywinder",
135
+ user: "github-changelog-generator",
93
136
  project: "changelog_test",
94
137
  token: INVALID_TOKEN
95
138
  }
@@ -102,39 +145,39 @@ describe GitHubChangelogGenerator::OctoFetcher do
102
145
 
103
146
  context "when API call is valid", :vcr do
104
147
  it "should return tags" do
105
- expected_tags = [{ "name" => "v0.0.3",
148
+ expected_tags = [{ "name" => "v0.0.3",
106
149
  "zipball_url" =>
107
150
  "https://api.github.com/repos/skywinder/changelog_test/zipball/v0.0.3",
108
151
  "tarball_url" =>
109
152
  "https://api.github.com/repos/skywinder/changelog_test/tarball/v0.0.3",
110
- "commit" =>
153
+ "commit" =>
111
154
  { "sha" => "a0cba2b1a1ea9011ab07ee1ac140ba5a5eb8bd90",
112
155
  "url" =>
113
156
  "https://api.github.com/repos/skywinder/changelog_test/commits/a0cba2b1a1ea9011ab07ee1ac140ba5a5eb8bd90" } },
114
- { "name" => "v0.0.2",
157
+ { "name" => "v0.0.2",
115
158
  "zipball_url" =>
116
159
  "https://api.github.com/repos/skywinder/changelog_test/zipball/v0.0.2",
117
160
  "tarball_url" =>
118
161
  "https://api.github.com/repos/skywinder/changelog_test/tarball/v0.0.2",
119
- "commit" =>
162
+ "commit" =>
120
163
  { "sha" => "9b35bb13dcd15b68e7bcbf10cde5eb937a54f710",
121
164
  "url" =>
122
165
  "https://api.github.com/repos/skywinder/changelog_test/commits/9b35bb13dcd15b68e7bcbf10cde5eb937a54f710" } },
123
- { "name" => "v0.0.1",
166
+ { "name" => "v0.0.1",
124
167
  "zipball_url" =>
125
168
  "https://api.github.com/repos/skywinder/changelog_test/zipball/v0.0.1",
126
169
  "tarball_url" =>
127
170
  "https://api.github.com/repos/skywinder/changelog_test/tarball/v0.0.1",
128
- "commit" =>
171
+ "commit" =>
129
172
  { "sha" => "4c2d6d1ed58bdb24b870dcb5d9f2ceed0283d69d",
130
173
  "url" =>
131
174
  "https://api.github.com/repos/skywinder/changelog_test/commits/4c2d6d1ed58bdb24b870dcb5d9f2ceed0283d69d" } },
132
- { "name" => "0.0.4",
175
+ { "name" => "0.0.4",
133
176
  "zipball_url" =>
134
177
  "https://api.github.com/repos/skywinder/changelog_test/zipball/0.0.4",
135
178
  "tarball_url" =>
136
179
  "https://api.github.com/repos/skywinder/changelog_test/tarball/0.0.4",
137
- "commit" =>
180
+ "commit" =>
138
181
  { "sha" => "ece0c3ab7142b21064b885061c55ede00ef6ce94",
139
182
  "url" =>
140
183
  "https://api.github.com/repos/skywinder/changelog_test/commits/ece0c3ab7142b21064b885061c55ede00ef6ce94" } }]
@@ -160,54 +203,54 @@ describe GitHubChangelogGenerator::OctoFetcher do
160
203
  it "returns issue with proper key/values" do
161
204
  issues, _pull_requests = fetcher.fetch_closed_issues_and_pr
162
205
 
163
- expected_issue = { "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/14",
206
+ expected_issue = { "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/14",
164
207
  "repository_url" => "https://api.github.com/repos/skywinder/changelog_test",
165
- "labels_url" =>
208
+ "labels_url" =>
166
209
  "https://api.github.com/repos/skywinder/changelog_test/issues/14/labels{/name}",
167
- "comments_url" =>
210
+ "comments_url" =>
168
211
  "https://api.github.com/repos/skywinder/changelog_test/issues/14/comments",
169
- "events_url" =>
212
+ "events_url" =>
170
213
  "https://api.github.com/repos/skywinder/changelog_test/issues/14/events",
171
- "html_url" => "https://github.com/skywinder/changelog_test/issues/14",
172
- "id" => 95_419_412,
173
- "number" => 14,
174
- "title" => "Issue closed from commit from PR",
175
- "user" =>
176
- { "login" => "skywinder",
177
- "id" => 3_356_474,
178
- "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
179
- "gravatar_id" => "",
180
- "url" => "https://api.github.com/users/skywinder",
181
- "html_url" => "https://github.com/skywinder",
182
- "followers_url" => "https://api.github.com/users/skywinder/followers",
183
- "following_url" =>
214
+ "html_url" => "https://github.com/skywinder/changelog_test/issues/14",
215
+ "id" => 95_419_412,
216
+ "number" => 14,
217
+ "title" => "Issue closed from commit from PR",
218
+ "user" =>
219
+ { "login" => "skywinder",
220
+ "id" => 3_356_474,
221
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
222
+ "gravatar_id" => "",
223
+ "url" => "https://api.github.com/users/skywinder",
224
+ "html_url" => "https://github.com/skywinder",
225
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
226
+ "following_url" =>
184
227
  "https://api.github.com/users/skywinder/following{/other_user}",
185
- "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
186
- "starred_url" =>
228
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
229
+ "starred_url" =>
187
230
  "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
188
- "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
189
- "organizations_url" => "https://api.github.com/users/skywinder/orgs",
190
- "repos_url" => "https://api.github.com/users/skywinder/repos",
191
- "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
231
+ "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
232
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
233
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
234
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
192
235
  "received_events_url" =>
193
236
  "https://api.github.com/users/skywinder/received_events",
194
- "type" => "User",
195
- "site_admin" => false },
196
- "labels" => [],
197
- "state" => "closed",
198
- "locked" => false,
199
- "assignee" => nil,
237
+ "type" => "User",
238
+ "site_admin" => false },
239
+ "labels" => [],
240
+ "state" => "closed",
241
+ "locked" => false,
242
+ "assignee" => nil,
200
243
  "assignees" => [],
201
- "milestone" => nil,
202
- "comments" => 0,
203
- "created_at" => "2015-07-16T12:06:08Z",
204
- "updated_at" => "2015-07-16T12:21:42Z",
205
- "closed_at" => "2015-07-16T12:21:42Z",
206
- "body" => "" }
244
+ "milestone" => nil,
245
+ "comments" => 0,
246
+ "created_at" => "2015-07-16T12:06:08Z",
247
+ "updated_at" => "2015-07-16T12:21:42Z",
248
+ "closed_at" => "2015-07-16T12:21:42Z",
249
+ "body" => "" }
207
250
 
208
251
  # Convert times to Time
209
252
  expected_issue.each_pair do |k, v|
210
- expected_issue[k] = Time.parse(v) if v =~ /^2015-/
253
+ expected_issue[k] = Time.parse(v) if v.to_s.start_with?("2015-")
211
254
  end
212
255
 
213
256
  expect(issues.first).to eq(expected_issue)
@@ -216,60 +259,60 @@ describe GitHubChangelogGenerator::OctoFetcher do
216
259
  it "returns pull request with proper key/values" do
217
260
  _issues, pull_requests = fetcher.fetch_closed_issues_and_pr
218
261
 
219
- expected_pr = { "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/21",
262
+ expected_pr = { "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/21",
220
263
  "repository_url" => "https://api.github.com/repos/skywinder/changelog_test",
221
- "labels_url" =>
264
+ "labels_url" =>
222
265
  "https://api.github.com/repos/skywinder/changelog_test/issues/21/labels{/name}",
223
- "comments_url" =>
266
+ "comments_url" =>
224
267
  "https://api.github.com/repos/skywinder/changelog_test/issues/21/comments",
225
- "events_url" =>
268
+ "events_url" =>
226
269
  "https://api.github.com/repos/skywinder/changelog_test/issues/21/events",
227
- "html_url" => "https://github.com/skywinder/changelog_test/pull/21",
228
- "id" => 124_925_759,
229
- "number" => 21,
230
- "title" => "Merged br (should appear in change log with #20)",
231
- "user" =>
232
- { "login" => "skywinder",
233
- "id" => 3_356_474,
234
- "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
235
- "gravatar_id" => "",
236
- "url" => "https://api.github.com/users/skywinder",
237
- "html_url" => "https://github.com/skywinder",
238
- "followers_url" => "https://api.github.com/users/skywinder/followers",
239
- "following_url" =>
270
+ "html_url" => "https://github.com/skywinder/changelog_test/pull/21",
271
+ "id" => 124_925_759,
272
+ "number" => 21,
273
+ "title" => "Merged br (should appear in change log with #20)",
274
+ "user" =>
275
+ { "login" => "skywinder",
276
+ "id" => 3_356_474,
277
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
278
+ "gravatar_id" => "",
279
+ "url" => "https://api.github.com/users/skywinder",
280
+ "html_url" => "https://github.com/skywinder",
281
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
282
+ "following_url" =>
240
283
  "https://api.github.com/users/skywinder/following{/other_user}",
241
- "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
242
- "starred_url" =>
284
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
285
+ "starred_url" =>
243
286
  "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
244
- "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
245
- "organizations_url" => "https://api.github.com/users/skywinder/orgs",
246
- "repos_url" => "https://api.github.com/users/skywinder/repos",
247
- "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
287
+ "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
288
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
289
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
290
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
248
291
  "received_events_url" =>
249
292
  "https://api.github.com/users/skywinder/received_events",
250
- "type" => "User",
251
- "site_admin" => false },
252
- "labels" => [],
253
- "state" => "closed",
254
- "locked" => false,
255
- "assignee" => nil,
293
+ "type" => "User",
294
+ "site_admin" => false },
295
+ "labels" => [],
296
+ "state" => "closed",
297
+ "locked" => false,
298
+ "assignee" => nil,
256
299
  "assignees" => [],
257
- "milestone" => nil,
258
- "comments" => 0,
259
- "created_at" => "2016-01-05T09:24:08Z",
260
- "updated_at" => "2016-01-05T09:26:53Z",
261
- "closed_at" => "2016-01-05T09:24:27Z",
262
- "pull_request" =>
263
- { "url" => "https://api.github.com/repos/skywinder/changelog_test/pulls/21",
264
- "html_url" => "https://github.com/skywinder/changelog_test/pull/21",
265
- "diff_url" => "https://github.com/skywinder/changelog_test/pull/21.diff",
300
+ "milestone" => nil,
301
+ "comments" => 0,
302
+ "created_at" => "2016-01-05T09:24:08Z",
303
+ "updated_at" => "2016-01-05T09:26:53Z",
304
+ "closed_at" => "2016-01-05T09:24:27Z",
305
+ "pull_request" =>
306
+ { "url" => "https://api.github.com/repos/skywinder/changelog_test/pulls/21",
307
+ "html_url" => "https://github.com/skywinder/changelog_test/pull/21",
308
+ "diff_url" => "https://github.com/skywinder/changelog_test/pull/21.diff",
266
309
  "patch_url" => "https://github.com/skywinder/changelog_test/pull/21.patch" },
267
- "body" =>
310
+ "body" =>
268
311
  "to test https://github.com/skywinder/github-changelog-generator/pull/305\r\nshould appear in change log with #20" }
269
312
 
270
313
  # Convert times to Time
271
314
  expected_pr.each_pair do |k, v|
272
- expected_pr[k] = Time.parse(v) if v =~ /^2016-01/
315
+ expected_pr[k] = Time.parse(v) if v.to_s.start_with?("2016-01")
273
316
  end
274
317
 
275
318
  expect(pull_requests.first).to eq(expected_pr)
@@ -308,51 +351,51 @@ describe GitHubChangelogGenerator::OctoFetcher do
308
351
  describe "#fetch_events_async" do
309
352
  context "when API call is valid", :vcr do
310
353
  it "populates issues" do
311
- issues = [{ "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/14",
354
+ issues = [{ "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/14",
312
355
  "repository_url" => "https://api.github.com/repos/skywinder/changelog_test",
313
- "labels_url" =>
356
+ "labels_url" =>
314
357
  "https://api.github.com/repos/skywinder/changelog_test/issues/14/labels{/name}",
315
- "comments_url" =>
358
+ "comments_url" =>
316
359
  "https://api.github.com/repos/skywinder/changelog_test/issues/14/comments",
317
- "events_url" =>
360
+ "events_url" =>
318
361
  "https://api.github.com/repos/skywinder/changelog_test/issues/14/events",
319
- "html_url" => "https://github.com/skywinder/changelog_test/issues/14",
320
- "id" => 95_419_412,
321
- "number" => 14,
322
- "title" => "Issue closed from commit from PR",
323
- "user" =>
324
- { "login" => "skywinder",
325
- "id" => 3_356_474,
326
- "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
327
- "gravatar_id" => "",
328
- "url" => "https://api.github.com/users/skywinder",
329
- "html_url" => "https://github.com/skywinder",
330
- "followers_url" => "https://api.github.com/users/skywinder/followers",
331
- "following_url" =>
362
+ "html_url" => "https://github.com/skywinder/changelog_test/issues/14",
363
+ "id" => 95_419_412,
364
+ "number" => 14,
365
+ "title" => "Issue closed from commit from PR",
366
+ "user" =>
367
+ { "login" => "skywinder",
368
+ "id" => 3_356_474,
369
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
370
+ "gravatar_id" => "",
371
+ "url" => "https://api.github.com/users/skywinder",
372
+ "html_url" => "https://github.com/skywinder",
373
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
374
+ "following_url" =>
332
375
  "https://api.github.com/users/skywinder/following{/other_user}",
333
- "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
334
- "starred_url" =>
376
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
377
+ "starred_url" =>
335
378
  "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
336
- "subscriptions_url" =>
379
+ "subscriptions_url" =>
337
380
  "https://api.github.com/users/skywinder/subscriptions",
338
- "organizations_url" => "https://api.github.com/users/skywinder/orgs",
339
- "repos_url" => "https://api.github.com/users/skywinder/repos",
340
- "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
381
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
382
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
383
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
341
384
  "received_events_url" =>
342
385
  "https://api.github.com/users/skywinder/received_events",
343
- "type" => "User",
344
- "site_admin" => false },
345
- "labels" => [],
346
- "state" => "closed",
347
- "locked" => false,
348
- "assignee" => nil,
386
+ "type" => "User",
387
+ "site_admin" => false },
388
+ "labels" => [],
389
+ "state" => "closed",
390
+ "locked" => false,
391
+ "assignee" => nil,
349
392
  "assignees" => [],
350
- "milestone" => nil,
351
- "comments" => 0,
352
- "created_at" => "2015-07-16T12:06:08Z",
353
- "updated_at" => "2015-07-16T12:21:42Z",
354
- "closed_at" => "2015-07-16T12:21:42Z",
355
- "body" => "" }]
393
+ "milestone" => nil,
394
+ "comments" => 0,
395
+ "created_at" => "2015-07-16T12:06:08Z",
396
+ "updated_at" => "2015-07-16T12:21:42Z",
397
+ "closed_at" => "2015-07-16T12:21:42Z",
398
+ "body" => "" }]
356
399
 
357
400
  # Check that they are blank to begin with
358
401
  expect(issues.first["events"]).to be_nil
@@ -360,63 +403,63 @@ describe GitHubChangelogGenerator::OctoFetcher do
360
403
  fetcher.fetch_events_async(issues)
361
404
  issue_events = issues.first["events"]
362
405
 
363
- expected_events = [{ "id" => 357_462_189,
364
- "url" =>
406
+ expected_events = [{ "id" => 357_462_189,
407
+ "url" =>
365
408
  "https://api.github.com/repos/skywinder/changelog_test/issues/events/357462189",
366
- "actor" =>
367
- { "login" => "skywinder",
368
- "id" => 3_356_474,
369
- "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
370
- "gravatar_id" => "",
371
- "url" => "https://api.github.com/users/skywinder",
372
- "html_url" => "https://github.com/skywinder",
373
- "followers_url" => "https://api.github.com/users/skywinder/followers",
374
- "following_url" =>
409
+ "actor" =>
410
+ { "login" => "skywinder",
411
+ "id" => 3_356_474,
412
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
413
+ "gravatar_id" => "",
414
+ "url" => "https://api.github.com/users/skywinder",
415
+ "html_url" => "https://github.com/skywinder",
416
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
417
+ "following_url" =>
375
418
  "https://api.github.com/users/skywinder/following{/other_user}",
376
- "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
377
- "starred_url" =>
419
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
420
+ "starred_url" =>
378
421
  "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
379
- "subscriptions_url" =>
422
+ "subscriptions_url" =>
380
423
  "https://api.github.com/users/skywinder/subscriptions",
381
- "organizations_url" => "https://api.github.com/users/skywinder/orgs",
382
- "repos_url" => "https://api.github.com/users/skywinder/repos",
383
- "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
424
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
425
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
426
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
384
427
  "received_events_url" =>
385
428
  "https://api.github.com/users/skywinder/received_events",
386
- "type" => "User",
387
- "site_admin" => false },
388
- "event" => "referenced",
389
- "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
429
+ "type" => "User",
430
+ "site_admin" => false },
431
+ "event" => "referenced",
432
+ "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
390
433
  "commit_url" =>
391
434
  "https://api.github.com/repos/skywinder/changelog_test/commits/decfe840d1a1b86e0c28700de5362d3365a29555",
392
435
  "created_at" => "2015-07-16T12:21:16Z" },
393
- { "id" => 357_462_542,
394
- "url" =>
436
+ { "id" => 357_462_542,
437
+ "url" =>
395
438
  "https://api.github.com/repos/skywinder/changelog_test/issues/events/357462542",
396
- "actor" =>
397
- { "login" => "skywinder",
398
- "id" => 3_356_474,
399
- "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
400
- "gravatar_id" => "",
401
- "url" => "https://api.github.com/users/skywinder",
402
- "html_url" => "https://github.com/skywinder",
403
- "followers_url" => "https://api.github.com/users/skywinder/followers",
404
- "following_url" =>
439
+ "actor" =>
440
+ { "login" => "skywinder",
441
+ "id" => 3_356_474,
442
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
443
+ "gravatar_id" => "",
444
+ "url" => "https://api.github.com/users/skywinder",
445
+ "html_url" => "https://github.com/skywinder",
446
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
447
+ "following_url" =>
405
448
  "https://api.github.com/users/skywinder/following{/other_user}",
406
- "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
407
- "starred_url" =>
449
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
450
+ "starred_url" =>
408
451
  "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
409
- "subscriptions_url" =>
452
+ "subscriptions_url" =>
410
453
  "https://api.github.com/users/skywinder/subscriptions",
411
- "organizations_url" => "https://api.github.com/users/skywinder/orgs",
412
- "repos_url" => "https://api.github.com/users/skywinder/repos",
413
- "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
454
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
455
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
456
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
414
457
  "received_events_url" =>
415
458
  "https://api.github.com/users/skywinder/received_events",
416
- "type" => "User",
417
- "site_admin" => false },
418
- "event" => "closed",
419
- "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
459
+ "type" => "User",
460
+ "site_admin" => false },
461
+ "event" => "closed",
462
+ "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
420
463
  "commit_url" =>
421
464
  "https://api.github.com/repos/skywinder/changelog_test/commits/decfe840d1a1b86e0c28700de5362d3365a29555",
422
465
  "created_at" => "2015-07-16T12:21:42Z" }]
@@ -424,7 +467,7 @@ describe GitHubChangelogGenerator::OctoFetcher do
424
467
  # Convert times to Time
425
468
  expected_events.map! do |event|
426
469
  event.each_pair do |k, v|
427
- event[k] = Time.parse(v) if v =~ /^201[56]-/
470
+ event[k] = Time.parse(v) if v.to_s =~ /^201[56]-/
428
471
  end
429
472
  end
430
473
 
@@ -436,17 +479,21 @@ describe GitHubChangelogGenerator::OctoFetcher do
436
479
  describe "#fetch_date_of_tag" do
437
480
  context "when API call is valid", :vcr do
438
481
  it "returns date" do
439
- tag = { "name" => "v0.0.3",
482
+ tag = { "name" => "v0.0.3",
440
483
  "zipball_url" =>
441
484
  "https://api.github.com/repos/skywinder/changelog_test/zipball/v0.0.3",
442
485
  "tarball_url" =>
443
486
  "https://api.github.com/repos/skywinder/changelog_test/tarball/v0.0.3",
444
- "commit" =>
487
+ "commit" =>
445
488
  { "sha" => "a0cba2b1a1ea9011ab07ee1ac140ba5a5eb8bd90",
446
489
  "url" =>
447
490
  "https://api.github.com/repos/skywinder/changelog_test/commits/a0cba2b1a1ea9011ab07ee1ac140ba5a5eb8bd90" } }
448
491
 
449
- dt = fetcher.fetch_date_of_tag(tag)
492
+ skywinder = GitHubChangelogGenerator::OctoFetcher.new(
493
+ user: "skywinder",
494
+ project: "changelog_test"
495
+ )
496
+ dt = skywinder.fetch_date_of_tag(tag)
450
497
  expect(dt).to eq(Time.parse("2015-03-04 19:01:48 UTC"))
451
498
  end
452
499
  end
@@ -469,36 +516,36 @@ describe GitHubChangelogGenerator::OctoFetcher do
469
516
  describe "#fetch_commit" do
470
517
  context "when API call is valid", :vcr do
471
518
  it "returns commit" do
472
- event = { "id" => 357_462_189,
473
- "url" =>
519
+ event = { "id" => 357_462_189,
520
+ "url" =>
474
521
  "https://api.github.com/repos/skywinder/changelog_test/issues/events/357462189",
475
- "actor" =>
476
- { "login" => "skywinder",
477
- "id" => 3_356_474,
478
- "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
479
- "gravatar_id" => "",
480
- "url" => "https://api.github.com/users/skywinder",
481
- "html_url" => "https://github.com/skywinder",
482
- "followers_url" => "https://api.github.com/users/skywinder/followers",
483
- "following_url" =>
522
+ "actor" =>
523
+ { "login" => "github-changelog-generator",
524
+ "id" => 3_356_474,
525
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
526
+ "gravatar_id" => "",
527
+ "url" => "https://api.github.com/users/skywinder",
528
+ "html_url" => "https://github.com/skywinder",
529
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
530
+ "following_url" =>
484
531
  "https://api.github.com/users/skywinder/following{/other_user}",
485
- "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
486
- "starred_url" =>
532
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
533
+ "starred_url" =>
487
534
  "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
488
- "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
489
- "organizations_url" => "https://api.github.com/users/skywinder/orgs",
490
- "repos_url" => "https://api.github.com/users/skywinder/repos",
491
- "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
535
+ "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
536
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
537
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
538
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
492
539
  "received_events_url" =>
493
540
  "https://api.github.com/users/skywinder/received_events",
494
- "type" => "User",
495
- "site_admin" => false },
496
- "event" => "referenced",
497
- "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
541
+ "type" => "User",
542
+ "site_admin" => false },
543
+ "event" => "referenced",
544
+ "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
498
545
  "commit_url" =>
499
546
  "https://api.github.com/repos/skywinder/changelog_test/commits/decfe840d1a1b86e0c28700de5362d3365a29555",
500
547
  "created_at" => "2015-07-16T12:21:16Z" }
501
- commit = fetcher.fetch_commit(event)
548
+ commit = fetcher.fetch_commit(event["commit_id"])
502
549
 
503
550
  expectations = [
504
551
  %w[sha decfe840d1a1b86e0c28700de5362d3365a29555],
@@ -508,9 +555,9 @@ describe GitHubChangelogGenerator::OctoFetcher do
508
555
  ["html_url",
509
556
  "https://github.com/skywinder/changelog_test/commit/decfe840d1a1b86e0c28700de5362d3365a29555"],
510
557
  ["author",
511
- { "login" => "skywinder", "id" => 3_356_474, "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3", "gravatar_id" => "", "url" => "https://api.github.com/users/skywinder", "html_url" => "https://github.com/skywinder", "followers_url" => "https://api.github.com/users/skywinder/followers", "following_url" => "https://api.github.com/users/skywinder/following{/other_user}", "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}", "starred_url" => "https://api.github.com/users/skywinder/starred{/owner}{/repo}", "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions", "organizations_url" => "https://api.github.com/users/skywinder/orgs", "repos_url" => "https://api.github.com/users/skywinder/repos", "events_url" => "https://api.github.com/users/skywinder/events{/privacy}", "received_events_url" => "https://api.github.com/users/skywinder/received_events", "type" => "User", "site_admin" => false }],
558
+ { "login" => "skywinder", "id" => 3_356_474, "avatar_url" => "https://avatars2.githubusercontent.com/u/3356474?v=4", "gravatar_id" => "", "url" => "https://api.github.com/users/skywinder", "html_url" => "https://github.com/skywinder", "followers_url" => "https://api.github.com/users/skywinder/followers", "following_url" => "https://api.github.com/users/skywinder/following{/other_user}", "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}", "starred_url" => "https://api.github.com/users/skywinder/starred{/owner}{/repo}", "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions", "organizations_url" => "https://api.github.com/users/skywinder/orgs", "repos_url" => "https://api.github.com/users/skywinder/repos", "events_url" => "https://api.github.com/users/skywinder/events{/privacy}", "received_events_url" => "https://api.github.com/users/skywinder/received_events", "type" => "User", "site_admin" => false }],
512
559
  ["committer",
513
- { "login" => "skywinder", "id" => 3_356_474, "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3", "gravatar_id" => "", "url" => "https://api.github.com/users/skywinder", "html_url" => "https://github.com/skywinder", "followers_url" => "https://api.github.com/users/skywinder/followers", "following_url" => "https://api.github.com/users/skywinder/following{/other_user}", "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}", "starred_url" => "https://api.github.com/users/skywinder/starred{/owner}{/repo}", "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions", "organizations_url" => "https://api.github.com/users/skywinder/orgs", "repos_url" => "https://api.github.com/users/skywinder/repos", "events_url" => "https://api.github.com/users/skywinder/events{/privacy}", "received_events_url" => "https://api.github.com/users/skywinder/received_events", "type" => "User", "site_admin" => false }],
560
+ { "login" => "skywinder", "id" => 3_356_474, "avatar_url" => "https://avatars2.githubusercontent.com/u/3356474?v=4", "gravatar_id" => "", "url" => "https://api.github.com/users/skywinder", "html_url" => "https://github.com/skywinder", "followers_url" => "https://api.github.com/users/skywinder/followers", "following_url" => "https://api.github.com/users/skywinder/following{/other_user}", "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}", "starred_url" => "https://api.github.com/users/skywinder/starred{/owner}{/repo}", "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions", "organizations_url" => "https://api.github.com/users/skywinder/orgs", "repos_url" => "https://api.github.com/users/skywinder/repos", "events_url" => "https://api.github.com/users/skywinder/events{/privacy}", "received_events_url" => "https://api.github.com/users/skywinder/received_events", "type" => "User", "site_admin" => false }],
514
561
  ["parents",
515
562
  [{ "sha" => "7ec095e5e3caceacedabf44d0b9b10da17c92e51",
516
563
  "url" =>
@@ -520,19 +567,22 @@ describe GitHubChangelogGenerator::OctoFetcher do
520
567
  "https://github.com/skywinder/changelog_test/commit/7ec095e5e3caceacedabf44d0b9b10da17c92e51" }]]
521
568
  ]
522
569
 
523
- expectations.each do |property, val|
524
- expect(commit[property]).to eq(val)
570
+ expectations.each do |property, value|
571
+ case value
572
+ when String, Array
573
+ expect(commit[property]).to eq(value)
574
+ when Hash
575
+ expect(commit[property]).to include(value)
576
+ end
525
577
  end
526
578
  end
527
579
  end
528
580
  end
529
581
 
530
- describe "#commits_before" do
582
+ describe "#commits" do
531
583
  context "when API is valid", :vcr do
532
- let(:start_time) { Time.parse("Wed Mar 4 18:47:17 2015 +0200") }
533
-
534
584
  subject do
535
- fetcher.commits_before(start_time)
585
+ fetcher.commits
536
586
  end
537
587
 
538
588
  it "returns commits" do