px_github_changelog_generator 0.0.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 (68) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +9 -0
  3. data/README.md +357 -0
  4. data/Rakefile +19 -0
  5. data/bin/git-generate-changelog +5 -0
  6. data/bin/github_changelog_generator +5 -0
  7. data/lib/github_changelog_generator/argv_parser.rb +225 -0
  8. data/lib/github_changelog_generator/file_parser_chooser.rb +27 -0
  9. data/lib/github_changelog_generator/generator/entry.rb +218 -0
  10. data/lib/github_changelog_generator/generator/generator.rb +177 -0
  11. data/lib/github_changelog_generator/generator/generator_fetcher.rb +202 -0
  12. data/lib/github_changelog_generator/generator/generator_processor.rb +237 -0
  13. data/lib/github_changelog_generator/generator/generator_tags.rb +210 -0
  14. data/lib/github_changelog_generator/generator/section.rb +129 -0
  15. data/lib/github_changelog_generator/helper.rb +37 -0
  16. data/lib/github_changelog_generator/octo_fetcher.rb +535 -0
  17. data/lib/github_changelog_generator/options.rb +159 -0
  18. data/lib/github_changelog_generator/parser.rb +89 -0
  19. data/lib/github_changelog_generator/parser_file.rb +101 -0
  20. data/lib/github_changelog_generator/reader.rb +88 -0
  21. data/lib/github_changelog_generator/ssl_certs/cacert.pem +3138 -0
  22. data/lib/github_changelog_generator/task.rb +68 -0
  23. data/lib/github_changelog_generator/version.rb +5 -0
  24. data/lib/github_changelog_generator.rb +49 -0
  25. data/man/git-generate-changelog.1 +393 -0
  26. data/man/git-generate-changelog.1.html +359 -0
  27. data/man/git-generate-changelog.html +270 -0
  28. data/man/git-generate-changelog.md +274 -0
  29. data/spec/files/angular.js.md +9395 -0
  30. data/spec/files/bundler.md +1911 -0
  31. data/spec/files/config_example +5 -0
  32. data/spec/files/github-changelog-generator.md +305 -0
  33. data/spec/github_changelog_generator_spec.rb +32 -0
  34. data/spec/install_gem_in_bundler.gemfile +5 -0
  35. data/spec/spec_helper.rb +74 -0
  36. data/spec/unit/generator/entry_spec.rb +766 -0
  37. data/spec/unit/generator/generator_processor_spec.rb +203 -0
  38. data/spec/unit/generator/generator_spec.rb +47 -0
  39. data/spec/unit/generator/generator_tags_spec.rb +337 -0
  40. data/spec/unit/generator/section_spec.rb +43 -0
  41. data/spec/unit/octo_fetcher_spec.rb +590 -0
  42. data/spec/unit/options_spec.rb +67 -0
  43. data/spec/unit/parser_file_spec.rb +94 -0
  44. data/spec/unit/parser_spec.rb +54 -0
  45. data/spec/unit/reader_spec.rb +120 -0
  46. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits/when_API_is_valid/returns_commits.json +1 -0
  47. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits_before/when_API_is_valid/returns_commits.json +1 -0
  48. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issue_with_proper_key/values.json +1 -0
  49. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues.json +1 -0
  50. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues_with_labels.json +1 -0
  51. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_pull_request_with_proper_key/values.json +1 -0
  52. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_pull_requests_with_labels.json +1 -0
  53. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid.json +1 -0
  54. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_correct_pull_request_keys.json +1 -0
  55. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_pull_requests.json +1 -0
  56. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid.json +1 -0
  57. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid/returns_commit.json +1 -0
  58. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid.json +1 -0
  59. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid/returns_date.json +1 -0
  60. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid.json +1 -0
  61. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid/populates_issues.json +1 -0
  62. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid.json +1 -0
  63. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags.json +1 -0
  64. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags_count.json +1 -0
  65. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid.json +1 -0
  66. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_wrong_token_provided/should_raise_Unauthorized_error.json +1 -0
  67. data/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_wrong_token_provided.json +1 -0
  68. metadata +250 -0
@@ -0,0 +1,590 @@
1
+ # frozen_string_literal: true
2
+
3
+ VALID_TOKEN = "0123456789abcdef"
4
+ INVALID_TOKEN = "0000000000000000"
5
+
6
+ describe GitHubChangelogGenerator::OctoFetcher do
7
+ let(:options) do
8
+ {
9
+ user: "github-changelog-generator",
10
+ project: "changelog_test"
11
+ }
12
+ end
13
+
14
+ let(:fetcher) { GitHubChangelogGenerator::OctoFetcher.new(options) }
15
+
16
+ describe "#check_github_response" do
17
+ context "when returns successfully" do
18
+ it "returns block value" do
19
+ expect(fetcher.send(:check_github_response) { 1 + 1 }).to eq(2)
20
+ end
21
+ end
22
+
23
+ context "when raises Octokit::Unauthorized" do
24
+ it "aborts" do
25
+ expect(fetcher).to receive(:sys_abort).with("Error: wrong GitHub token")
26
+ fetcher.send(:check_github_response) { raise(Octokit::Unauthorized) }
27
+ end
28
+ end
29
+
30
+ context "when raises Octokit::Forbidden" do
31
+ it "sleeps and retries and then aborts" do
32
+ expect(fetcher).to receive(:sys_abort).with("Exceeded retry limit")
33
+ fetcher.send(:check_github_response) { raise(Octokit::Forbidden) }
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "#fetch_github_token" do
39
+ token = GitHubChangelogGenerator::OctoFetcher::CHANGELOG_GITHUB_TOKEN
40
+ context "when token in ENV exist" do
41
+ before { stub_const("ENV", ENV.to_hash.merge(token => VALID_TOKEN)) }
42
+ subject { fetcher.send(:fetch_github_token) }
43
+ it { is_expected.to eq(VALID_TOKEN) }
44
+ end
45
+
46
+ context "when token in ENV is nil" do
47
+ before { stub_const("ENV", ENV.to_hash.merge(token => nil)) }
48
+ subject { fetcher.send(:fetch_github_token) }
49
+ it { is_expected.to be_nil }
50
+ end
51
+
52
+ context "when token in options and ENV is nil" do
53
+ let(:options) { { token: VALID_TOKEN } }
54
+
55
+ before do
56
+ stub_const("ENV", ENV.to_hash.merge(token => nil))
57
+ end
58
+
59
+ subject { fetcher.send(:fetch_github_token) }
60
+ it { is_expected.to eq(VALID_TOKEN) }
61
+ end
62
+
63
+ context "when token in options and ENV specified" do
64
+ let(:options) { { token: VALID_TOKEN } }
65
+
66
+ before do
67
+ stub_const("ENV", ENV.to_hash.merge(token => "no_matter_what"))
68
+ end
69
+
70
+ subject { fetcher.send(:fetch_github_token) }
71
+ it { is_expected.to eq(VALID_TOKEN) }
72
+ end
73
+ end
74
+
75
+ describe "#fetch_all_tags" do
76
+ context "when github_fetch_tags returns tags" do
77
+ it "returns tags" do
78
+ mock_tags = ["tag"]
79
+ allow(fetcher).to receive(:github_fetch_tags).and_return(mock_tags)
80
+ expect(fetcher.fetch_all_tags).to eq(mock_tags)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe "#fetch_tag_shas" do
86
+ let(:commits) do
87
+ [
88
+ { sha: "0", parents: [{ sha: "1" }, { sha: "6" }] },
89
+ { sha: "1", parents: [{ sha: "2" }] },
90
+ { sha: "2", parents: [{ sha: "3" }] },
91
+ { sha: "3", parents: [{ sha: "4" }] },
92
+ { sha: "4", parents: [{ sha: "5" }] },
93
+ { sha: "5", parents: [] },
94
+ { sha: "6", parents: [{ sha: "7" }, { sha: "8" }] },
95
+ { sha: "7", parents: [{ sha: "9" }, { sha: "10" }] },
96
+ { sha: "8", parents: [{ sha: "11" }, { sha: "12" }] },
97
+ { sha: "9", parents: [] },
98
+ { sha: "10", parents: [] },
99
+ { sha: "11", parents: [] },
100
+ { sha: "12", parents: [] }
101
+ ]
102
+ end
103
+
104
+ let(:tag0) { { "name" => "tag-0", "commit" => { "sha" => "0" } } }
105
+ let(:tag1) { { "name" => "tag-1", "commit" => { "sha" => "1" } } }
106
+ let(:tag6) { { "name" => "tag-6", "commit" => { "sha" => "6" } } }
107
+
108
+ before do
109
+ allow(fetcher).to receive(:commits).and_return(commits)
110
+ end
111
+
112
+ it "should find all shas with single parents" do
113
+ fetcher.fetch_tag_shas([tag1])
114
+ expect(tag1["shas_in_tag"]).to eq(Set.new(%w[1 2 3 4 5]))
115
+ end
116
+
117
+ it "should find all shas with multiple parents" do
118
+ fetcher.fetch_tag_shas([tag6])
119
+ expect(tag6["shas_in_tag"]).to eq(Set.new(%w[6 7 8 9 10 11 12]))
120
+ end
121
+
122
+ it "should find all shas with mixed parents" do
123
+ fetcher.fetch_tag_shas([tag0])
124
+ expect(tag0["shas_in_tag"]).to eq(Set.new(%w[0 1 2 3 4 5 6 7 8 9 10 11 12]))
125
+ end
126
+ end
127
+
128
+ describe "#github_fetch_tags" do
129
+ context "when wrong token provided", :vcr do
130
+ let(:options) do
131
+ {
132
+ user: "github-changelog-generator",
133
+ project: "changelog_test",
134
+ token: INVALID_TOKEN
135
+ }
136
+ end
137
+
138
+ it "should raise Unauthorized error" do
139
+ expect { fetcher.github_fetch_tags }.to raise_error SystemExit, "Error: wrong GitHub token"
140
+ end
141
+ end
142
+
143
+ context "when API call is valid", :vcr do
144
+ it "should return tags" do
145
+ expected_tags = [{ "name" => "v0.0.3",
146
+ "zipball_url" =>
147
+ "https://api.github.com/repos/skywinder/changelog_test/zipball/v0.0.3",
148
+ "tarball_url" =>
149
+ "https://api.github.com/repos/skywinder/changelog_test/tarball/v0.0.3",
150
+ "commit" =>
151
+ { "sha" => "a0cba2b1a1ea9011ab07ee1ac140ba5a5eb8bd90",
152
+ "url" =>
153
+ "https://api.github.com/repos/skywinder/changelog_test/commits/a0cba2b1a1ea9011ab07ee1ac140ba5a5eb8bd90" } },
154
+ { "name" => "v0.0.2",
155
+ "zipball_url" =>
156
+ "https://api.github.com/repos/skywinder/changelog_test/zipball/v0.0.2",
157
+ "tarball_url" =>
158
+ "https://api.github.com/repos/skywinder/changelog_test/tarball/v0.0.2",
159
+ "commit" =>
160
+ { "sha" => "9b35bb13dcd15b68e7bcbf10cde5eb937a54f710",
161
+ "url" =>
162
+ "https://api.github.com/repos/skywinder/changelog_test/commits/9b35bb13dcd15b68e7bcbf10cde5eb937a54f710" } },
163
+ { "name" => "v0.0.1",
164
+ "zipball_url" =>
165
+ "https://api.github.com/repos/skywinder/changelog_test/zipball/v0.0.1",
166
+ "tarball_url" =>
167
+ "https://api.github.com/repos/skywinder/changelog_test/tarball/v0.0.1",
168
+ "commit" =>
169
+ { "sha" => "4c2d6d1ed58bdb24b870dcb5d9f2ceed0283d69d",
170
+ "url" =>
171
+ "https://api.github.com/repos/skywinder/changelog_test/commits/4c2d6d1ed58bdb24b870dcb5d9f2ceed0283d69d" } },
172
+ { "name" => "0.0.4",
173
+ "zipball_url" =>
174
+ "https://api.github.com/repos/skywinder/changelog_test/zipball/0.0.4",
175
+ "tarball_url" =>
176
+ "https://api.github.com/repos/skywinder/changelog_test/tarball/0.0.4",
177
+ "commit" =>
178
+ { "sha" => "ece0c3ab7142b21064b885061c55ede00ef6ce94",
179
+ "url" =>
180
+ "https://api.github.com/repos/skywinder/changelog_test/commits/ece0c3ab7142b21064b885061c55ede00ef6ce94" } }]
181
+
182
+ expect(fetcher.github_fetch_tags).to eq(expected_tags)
183
+ end
184
+
185
+ it "should return tags count" do
186
+ tags = fetcher.github_fetch_tags
187
+ expect(tags.size).to eq(4)
188
+ end
189
+ end
190
+ end
191
+
192
+ describe "#fetch_closed_issues_and_pr" do
193
+ context "when API call is valid", :vcr do
194
+ it "returns issues" do
195
+ issues, pull_requests = fetcher.fetch_closed_issues_and_pr
196
+ expect(issues.size).to eq(7)
197
+ expect(pull_requests.size).to eq(14)
198
+ end
199
+
200
+ it "returns issue with proper key/values" do
201
+ issues, _pull_requests = fetcher.fetch_closed_issues_and_pr
202
+
203
+ expected_issue = { "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/14",
204
+ "repository_url" => "https://api.github.com/repos/skywinder/changelog_test",
205
+ "labels_url" =>
206
+ "https://api.github.com/repos/skywinder/changelog_test/issues/14/labels{/name}",
207
+ "comments_url" =>
208
+ "https://api.github.com/repos/skywinder/changelog_test/issues/14/comments",
209
+ "events_url" =>
210
+ "https://api.github.com/repos/skywinder/changelog_test/issues/14/events",
211
+ "html_url" => "https://github.com/skywinder/changelog_test/issues/14",
212
+ "id" => 95_419_412,
213
+ "number" => 14,
214
+ "title" => "Issue closed from commit from PR",
215
+ "user" =>
216
+ { "login" => "skywinder",
217
+ "id" => 3_356_474,
218
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
219
+ "gravatar_id" => "",
220
+ "url" => "https://api.github.com/users/skywinder",
221
+ "html_url" => "https://github.com/skywinder",
222
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
223
+ "following_url" =>
224
+ "https://api.github.com/users/skywinder/following{/other_user}",
225
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
226
+ "starred_url" =>
227
+ "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
228
+ "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
229
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
230
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
231
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
232
+ "received_events_url" =>
233
+ "https://api.github.com/users/skywinder/received_events",
234
+ "type" => "User",
235
+ "site_admin" => false },
236
+ "labels" => [],
237
+ "state" => "closed",
238
+ "locked" => false,
239
+ "assignee" => nil,
240
+ "assignees" => [],
241
+ "milestone" => nil,
242
+ "comments" => 0,
243
+ "created_at" => "2015-07-16T12:06:08Z",
244
+ "updated_at" => "2015-07-16T12:21:42Z",
245
+ "closed_at" => "2015-07-16T12:21:42Z",
246
+ "body" => "" }
247
+
248
+ # Convert times to Time
249
+ expected_issue.each_pair do |k, v|
250
+ expected_issue[k] = Time.parse(v) if v.to_s.start_with?("2015-")
251
+ end
252
+
253
+ expect(issues.first).to eq(expected_issue)
254
+ end
255
+
256
+ it "returns pull request with proper key/values" do
257
+ _issues, pull_requests = fetcher.fetch_closed_issues_and_pr
258
+
259
+ expected_pr = { "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/21",
260
+ "repository_url" => "https://api.github.com/repos/skywinder/changelog_test",
261
+ "labels_url" =>
262
+ "https://api.github.com/repos/skywinder/changelog_test/issues/21/labels{/name}",
263
+ "comments_url" =>
264
+ "https://api.github.com/repos/skywinder/changelog_test/issues/21/comments",
265
+ "events_url" =>
266
+ "https://api.github.com/repos/skywinder/changelog_test/issues/21/events",
267
+ "html_url" => "https://github.com/skywinder/changelog_test/pull/21",
268
+ "id" => 124_925_759,
269
+ "number" => 21,
270
+ "title" => "Merged br (should appear in change log with #20)",
271
+ "user" =>
272
+ { "login" => "skywinder",
273
+ "id" => 3_356_474,
274
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
275
+ "gravatar_id" => "",
276
+ "url" => "https://api.github.com/users/skywinder",
277
+ "html_url" => "https://github.com/skywinder",
278
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
279
+ "following_url" =>
280
+ "https://api.github.com/users/skywinder/following{/other_user}",
281
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
282
+ "starred_url" =>
283
+ "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
284
+ "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
285
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
286
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
287
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
288
+ "received_events_url" =>
289
+ "https://api.github.com/users/skywinder/received_events",
290
+ "type" => "User",
291
+ "site_admin" => false },
292
+ "labels" => [],
293
+ "state" => "closed",
294
+ "locked" => false,
295
+ "assignee" => nil,
296
+ "assignees" => [],
297
+ "milestone" => nil,
298
+ "comments" => 0,
299
+ "created_at" => "2016-01-05T09:24:08Z",
300
+ "updated_at" => "2016-01-05T09:26:53Z",
301
+ "closed_at" => "2016-01-05T09:24:27Z",
302
+ "pull_request" =>
303
+ { "url" => "https://api.github.com/repos/skywinder/changelog_test/pulls/21",
304
+ "html_url" => "https://github.com/skywinder/changelog_test/pull/21",
305
+ "diff_url" => "https://github.com/skywinder/changelog_test/pull/21.diff",
306
+ "patch_url" => "https://github.com/skywinder/changelog_test/pull/21.patch" },
307
+ "body" =>
308
+ "to test https://github.com/skywinder/github-changelog-generator/pull/305\r\nshould appear in change log with #20" }
309
+
310
+ # Convert times to Time
311
+ expected_pr.each_pair do |k, v|
312
+ expected_pr[k] = Time.parse(v) if v.to_s.start_with?("2016-01")
313
+ end
314
+
315
+ expect(pull_requests.first).to eq(expected_pr)
316
+ end
317
+
318
+ it "returns issues with labels" do
319
+ issues, _pull_requests = fetcher.fetch_closed_issues_and_pr
320
+ expected = [[], [], ["Bug"], [], ["enhancement"], ["some label"], []]
321
+ expect(issues.map { |i| i["labels"].map { |l| l["name"] } }).to eq(expected)
322
+ end
323
+
324
+ it "returns pull_requests with labels" do
325
+ _issues, pull_requests = fetcher.fetch_closed_issues_and_pr
326
+ expected = [[], [], [], [], [], ["enhancement"], [], [], ["invalid"], [], [], [], [], ["invalid"]]
327
+ expect(pull_requests.map { |i| i["labels"].map { |l| l["name"] } }).to eq(expected)
328
+ end
329
+ end
330
+ end
331
+
332
+ describe "#fetch_closed_pull_requests" do
333
+ context "when API call is valid", :vcr do
334
+ it "returns pull requests" do
335
+ pull_requests = fetcher.fetch_closed_pull_requests
336
+ expect(pull_requests.size).to eq(14)
337
+ end
338
+
339
+ it "returns correct pull request keys" do
340
+ pull_requests = fetcher.fetch_closed_pull_requests
341
+
342
+ pr = pull_requests.first
343
+ expect(pr.keys).to eq(%w[url id html_url diff_url patch_url issue_url number state locked title user body created_at updated_at closed_at merged_at merge_commit_sha assignee assignees milestone commits_url review_comments_url review_comment_url comments_url statuses_url head base _links])
344
+ end
345
+ end
346
+ end
347
+
348
+ describe "#fetch_events_async" do
349
+ context "when API call is valid", :vcr do
350
+ it "populates issues" do
351
+ issues = [{ "url" => "https://api.github.com/repos/skywinder/changelog_test/issues/14",
352
+ "repository_url" => "https://api.github.com/repos/skywinder/changelog_test",
353
+ "labels_url" =>
354
+ "https://api.github.com/repos/skywinder/changelog_test/issues/14/labels{/name}",
355
+ "comments_url" =>
356
+ "https://api.github.com/repos/skywinder/changelog_test/issues/14/comments",
357
+ "events_url" =>
358
+ "https://api.github.com/repos/skywinder/changelog_test/issues/14/events",
359
+ "html_url" => "https://github.com/skywinder/changelog_test/issues/14",
360
+ "id" => 95_419_412,
361
+ "number" => 14,
362
+ "title" => "Issue closed from commit from PR",
363
+ "user" =>
364
+ { "login" => "skywinder",
365
+ "id" => 3_356_474,
366
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
367
+ "gravatar_id" => "",
368
+ "url" => "https://api.github.com/users/skywinder",
369
+ "html_url" => "https://github.com/skywinder",
370
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
371
+ "following_url" =>
372
+ "https://api.github.com/users/skywinder/following{/other_user}",
373
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
374
+ "starred_url" =>
375
+ "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
376
+ "subscriptions_url" =>
377
+ "https://api.github.com/users/skywinder/subscriptions",
378
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
379
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
380
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
381
+ "received_events_url" =>
382
+ "https://api.github.com/users/skywinder/received_events",
383
+ "type" => "User",
384
+ "site_admin" => false },
385
+ "labels" => [],
386
+ "state" => "closed",
387
+ "locked" => false,
388
+ "assignee" => nil,
389
+ "assignees" => [],
390
+ "milestone" => nil,
391
+ "comments" => 0,
392
+ "created_at" => "2015-07-16T12:06:08Z",
393
+ "updated_at" => "2015-07-16T12:21:42Z",
394
+ "closed_at" => "2015-07-16T12:21:42Z",
395
+ "body" => "" }]
396
+
397
+ # Check that they are blank to begin with
398
+ expect(issues.first["events"]).to be_nil
399
+
400
+ fetcher.fetch_events_async(issues)
401
+ issue_events = issues.first["events"]
402
+
403
+ expected_events = [{ "id" => 357_462_189,
404
+ "url" =>
405
+ "https://api.github.com/repos/skywinder/changelog_test/issues/events/357462189",
406
+ "actor" =>
407
+ { "login" => "skywinder",
408
+ "id" => 3_356_474,
409
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
410
+ "gravatar_id" => "",
411
+ "url" => "https://api.github.com/users/skywinder",
412
+ "html_url" => "https://github.com/skywinder",
413
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
414
+ "following_url" =>
415
+ "https://api.github.com/users/skywinder/following{/other_user}",
416
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
417
+ "starred_url" =>
418
+ "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
419
+ "subscriptions_url" =>
420
+ "https://api.github.com/users/skywinder/subscriptions",
421
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
422
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
423
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
424
+ "received_events_url" =>
425
+ "https://api.github.com/users/skywinder/received_events",
426
+ "type" => "User",
427
+ "site_admin" => false },
428
+ "event" => "referenced",
429
+ "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
430
+ "commit_url" =>
431
+ "https://api.github.com/repos/skywinder/changelog_test/commits/decfe840d1a1b86e0c28700de5362d3365a29555",
432
+ "created_at" => "2015-07-16T12:21:16Z" },
433
+ { "id" => 357_462_542,
434
+ "url" =>
435
+ "https://api.github.com/repos/skywinder/changelog_test/issues/events/357462542",
436
+ "actor" =>
437
+ { "login" => "skywinder",
438
+ "id" => 3_356_474,
439
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
440
+ "gravatar_id" => "",
441
+ "url" => "https://api.github.com/users/skywinder",
442
+ "html_url" => "https://github.com/skywinder",
443
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
444
+ "following_url" =>
445
+ "https://api.github.com/users/skywinder/following{/other_user}",
446
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
447
+ "starred_url" =>
448
+ "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
449
+ "subscriptions_url" =>
450
+ "https://api.github.com/users/skywinder/subscriptions",
451
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
452
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
453
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
454
+ "received_events_url" =>
455
+ "https://api.github.com/users/skywinder/received_events",
456
+ "type" => "User",
457
+ "site_admin" => false },
458
+ "event" => "closed",
459
+ "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
460
+ "commit_url" =>
461
+ "https://api.github.com/repos/skywinder/changelog_test/commits/decfe840d1a1b86e0c28700de5362d3365a29555",
462
+ "created_at" => "2015-07-16T12:21:42Z" }]
463
+
464
+ # Convert times to Time
465
+ expected_events.map! do |event|
466
+ event.each_pair do |k, v|
467
+ event[k] = Time.parse(v) if v.to_s =~ /^201[56]-/
468
+ end
469
+ end
470
+
471
+ expect(issue_events).to eq(expected_events)
472
+ end
473
+ end
474
+ end
475
+
476
+ describe "#fetch_date_of_tag" do
477
+ context "when API call is valid", :vcr do
478
+ it "returns date" do
479
+ tag = { "name" => "v0.0.3",
480
+ "zipball_url" =>
481
+ "https://api.github.com/repos/skywinder/changelog_test/zipball/v0.0.3",
482
+ "tarball_url" =>
483
+ "https://api.github.com/repos/skywinder/changelog_test/tarball/v0.0.3",
484
+ "commit" =>
485
+ { "sha" => "a0cba2b1a1ea9011ab07ee1ac140ba5a5eb8bd90",
486
+ "url" =>
487
+ "https://api.github.com/repos/skywinder/changelog_test/commits/a0cba2b1a1ea9011ab07ee1ac140ba5a5eb8bd90" } }
488
+
489
+ skywinder = GitHubChangelogGenerator::OctoFetcher.new(
490
+ user: "skywinder",
491
+ project: "changelog_test"
492
+ )
493
+ dt = skywinder.fetch_date_of_tag(tag)
494
+ expect(dt).to eq(Time.parse("2015-03-04 19:01:48 UTC"))
495
+ end
496
+ end
497
+ end
498
+
499
+ describe "#querystring_as_hash" do
500
+ it "works on the blank URL" do
501
+ expect { fetcher.send(:querystring_as_hash, "") }.not_to raise_error
502
+ end
503
+
504
+ it "where there are no querystring params" do
505
+ expect { fetcher.send(:querystring_as_hash, "http://example.com") }.not_to raise_error
506
+ end
507
+
508
+ it "returns a String-keyed Hash of querystring params" do
509
+ expect(fetcher.send(:querystring_as_hash, "http://example.com/o.html?str=18&wis=12")).to include("wis" => "12", "str" => "18")
510
+ end
511
+ end
512
+
513
+ describe "#fetch_commit" do
514
+ context "when API call is valid", :vcr do
515
+ it "returns commit" do
516
+ event = { "id" => 357_462_189,
517
+ "url" =>
518
+ "https://api.github.com/repos/skywinder/changelog_test/issues/events/357462189",
519
+ "actor" =>
520
+ { "login" => "github-changelog-generator",
521
+ "id" => 3_356_474,
522
+ "avatar_url" => "https://avatars.githubusercontent.com/u/3356474?v=3",
523
+ "gravatar_id" => "",
524
+ "url" => "https://api.github.com/users/skywinder",
525
+ "html_url" => "https://github.com/skywinder",
526
+ "followers_url" => "https://api.github.com/users/skywinder/followers",
527
+ "following_url" =>
528
+ "https://api.github.com/users/skywinder/following{/other_user}",
529
+ "gists_url" => "https://api.github.com/users/skywinder/gists{/gist_id}",
530
+ "starred_url" =>
531
+ "https://api.github.com/users/skywinder/starred{/owner}{/repo}",
532
+ "subscriptions_url" => "https://api.github.com/users/skywinder/subscriptions",
533
+ "organizations_url" => "https://api.github.com/users/skywinder/orgs",
534
+ "repos_url" => "https://api.github.com/users/skywinder/repos",
535
+ "events_url" => "https://api.github.com/users/skywinder/events{/privacy}",
536
+ "received_events_url" =>
537
+ "https://api.github.com/users/skywinder/received_events",
538
+ "type" => "User",
539
+ "site_admin" => false },
540
+ "event" => "referenced",
541
+ "commit_id" => "decfe840d1a1b86e0c28700de5362d3365a29555",
542
+ "commit_url" =>
543
+ "https://api.github.com/repos/skywinder/changelog_test/commits/decfe840d1a1b86e0c28700de5362d3365a29555",
544
+ "created_at" => "2015-07-16T12:21:16Z" }
545
+ commit = fetcher.fetch_commit(event["commit_id"])
546
+
547
+ expectations = [
548
+ %w[sha decfe840d1a1b86e0c28700de5362d3365a29555],
549
+ ["url",
550
+ "https://api.github.com/repos/github-changelog-generator/changelog_test/commits/decfe840d1a1b86e0c28700de5362d3365a29555"],
551
+ # OLD API: "https://api.github.com/repos/skywinder/changelog_test/git/commits/decfe840d1a1b86e0c28700de5362d3365a29555"],
552
+ ["html_url",
553
+ "https://github.com/github-changelog-generator/changelog_test/commit/decfe840d1a1b86e0c28700de5362d3365a29555"],
554
+ ["author",
555
+ { "login" => "skywinder", "node_id" => "MDQ6VXNlcjMzNTY0NzQ=", "id" => 3_356_474, "avatar_url" => "https://avatars.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 }],
556
+ ["committer",
557
+ { "login" => "skywinder", "node_id" => "MDQ6VXNlcjMzNTY0NzQ=", "id" => 3_356_474, "avatar_url" => "https://avatars.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 }],
558
+ ["parents",
559
+ [{ "sha" => "7ec095e5e3caceacedabf44d0b9b10da17c92e51",
560
+ "url" =>
561
+ "https://api.github.com/repos/github-changelog-generator/changelog_test/commits/7ec095e5e3caceacedabf44d0b9b10da17c92e51",
562
+ # OLD API: "https://api.github.com/repos/skywinder/changelog_test/git/commits/7ec095e5e3caceacedabf44d0b9b10da17c92e51",
563
+ "html_url" =>
564
+ "https://github.com/github-changelog-generator/changelog_test/commit/7ec095e5e3caceacedabf44d0b9b10da17c92e51" }]]
565
+ ]
566
+
567
+ expectations.each do |property, value|
568
+ case value
569
+ when String, Array
570
+ expect(commit[property]).to eq(value)
571
+ when Hash
572
+ expect(commit[property]).to include(value)
573
+ end
574
+ end
575
+ end
576
+ end
577
+ end
578
+
579
+ describe "#commits" do
580
+ context "when API is valid", :vcr do
581
+ subject do
582
+ fetcher.commits
583
+ end
584
+
585
+ it "returns commits" do
586
+ expect(subject.last["sha"]).to eq("4c2d6d1ed58bdb24b870dcb5d9f2ceed0283d69d")
587
+ end
588
+ end
589
+ end
590
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe GitHubChangelogGenerator::Options do
4
+ describe "#initialize" do
5
+ context "with known options" do
6
+ it "instantiates successfully" do
7
+ expect(described_class.new(user: "olle")[:user]).to eq("olle")
8
+ end
9
+ end
10
+
11
+ context "with unknown options" do
12
+ it "raises an error" do
13
+ expect do
14
+ described_class.new(
15
+ project: "rails",
16
+ strength: "super-strength",
17
+ wisdom: "deep"
18
+ )
19
+ end.to raise_error("[:strength, :wisdom]")
20
+ end
21
+ end
22
+ end
23
+
24
+ describe "#[]=(key, value)" do
25
+ let(:options) { described_class.new(project: "rails") }
26
+
27
+ context "with known options" do
28
+ it "sets the option value" do
29
+ expect do
30
+ options[:project] = "trails"
31
+ end.to change { options[:project] }.to "trails"
32
+ end
33
+ end
34
+
35
+ context "with unknown options" do
36
+ it "raises an error" do
37
+ expect do
38
+ options[:charisma] = 8
39
+ end.to raise_error(":charisma")
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#write_to_file?" do
45
+ subject { options.write_to_file? }
46
+
47
+ let(:options) { described_class.new(output: output) }
48
+
49
+ context "with filename" do
50
+ let(:output) { "CHANGELOG.md" }
51
+
52
+ it { is_expected.to eq true }
53
+ end
54
+
55
+ context "with nil" do
56
+ let(:output) { nil }
57
+
58
+ it { is_expected.to eq false }
59
+ end
60
+
61
+ context "with empty string" do
62
+ let(:output) { "" }
63
+
64
+ it { is_expected.to eq false }
65
+ end
66
+ end
67
+ end