px_github_changelog_generator 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GitHubChangelogGenerator
4
+ describe Generator do
5
+ let(:default_options) { GitHubChangelogGenerator::Parser.default_options.merge(verbose: false) }
6
+ let(:options) { {} }
7
+ let(:generator) { described_class.new(default_options.merge(options)) }
8
+ let(:bad_label) { { "name" => "BAD" } }
9
+ let(:good_label) { { "name" => "GOOD" } }
10
+
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] }
16
+
17
+ describe "#filter_wo_labels" do
18
+ subject do
19
+ generator.filter_wo_labels(pull_requests)
20
+ end
21
+
22
+ let(:expected_pull_requests) { pull_requests }
23
+
24
+ it { is_expected.to eq(expected_pull_requests) }
25
+
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] }
29
+
30
+ it { is_expected.to eq(expected_pull_requests) }
31
+ end
32
+
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) }
37
+ end
38
+ end
39
+ end
40
+
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] }
46
+
47
+ describe "#filter_wo_labels" do
48
+ subject do
49
+ generator.filter_wo_labels(issues)
50
+ end
51
+
52
+ let(:expected_issues) { issues }
53
+
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
68
+ end
69
+
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 }
76
+
77
+ it { is_expected.to eq(expected_issues) }
78
+
79
+ context "when 'exclude_labels' is provided" do
80
+ let(:options) { { exclude_labels: %w[BAD BOO] } }
81
+ let(:expected_issues) { [good_issue, unlabeled_issue] }
82
+
83
+ it { is_expected.to eq(expected_issues) }
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
94
+ end
95
+
96
+ describe "#get_filtered_issues" do
97
+ subject do
98
+ generator.get_filtered_issues(issues)
99
+ end
100
+
101
+ let(:expected_issues) { issues }
102
+
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
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
201
+ end
202
+ end
203
+ 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
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe GitHubChangelogGenerator::Generator do
4
+ def tag_with_name(tag)
5
+ {
6
+ "name" => tag
7
+ }
8
+ end
9
+
10
+ def tags_from_strings(tags_strings)
11
+ tags_strings.map do |tag|
12
+ tag_with_name(tag)
13
+ end
14
+ end
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
+
43
+ describe "#tag_section_mapping" do
44
+ let(:all_tags) { tags_from_strings(%w[8 7 6 5 4 3 2 1]) }
45
+ let(:sorted_tags) { all_tags }
46
+
47
+ let(:default_options) { GitHubChangelogGenerator::Parser.default_options.merge(verbose: false) }
48
+ let(:options) { {} }
49
+ let(:generator) { described_class.new(default_options.merge(options)) }
50
+
51
+ before do
52
+ allow_any_instance_of(GitHubChangelogGenerator::OctoFetcher).to receive(:fetch_all_tags).and_return(all_tags)
53
+ allow(generator).to receive(:fetch_tags_dates).with(all_tags)
54
+ allow(generator).to receive(:sort_tags_by_date).with(all_tags).and_return(sorted_tags)
55
+ generator.fetch_and_filter_tags
56
+ end
57
+
58
+ subject do
59
+ generator.tag_section_mapping
60
+ end
61
+
62
+ shared_examples_for "a section mapping" do
63
+ it { is_expected.to be_a(Hash) }
64
+ it { is_expected.to eq(expected_mapping) }
65
+ end
66
+
67
+ shared_examples_for "a full changelog" do
68
+ let(:expected_mapping) do
69
+ {
70
+ tag_with_name("8") => [tag_with_name("7"), tag_with_name("8")],
71
+ tag_with_name("7") => [tag_with_name("6"), tag_with_name("7")],
72
+ tag_with_name("6") => [tag_with_name("5"), tag_with_name("6")],
73
+ tag_with_name("5") => [tag_with_name("4"), tag_with_name("5")],
74
+ tag_with_name("4") => [tag_with_name("3"), tag_with_name("4")],
75
+ tag_with_name("3") => [tag_with_name("2"), tag_with_name("3")],
76
+ tag_with_name("2") => [tag_with_name("1"), tag_with_name("2")],
77
+ tag_with_name("1") => [nil, tag_with_name("1")]
78
+ }
79
+ end
80
+
81
+ it_behaves_like "a section mapping"
82
+ end
83
+
84
+ shared_examples_for "a changelog with some exclusions" do
85
+ let(:expected_mapping) do
86
+ {
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")],
89
+ tag_with_name("4") => [tag_with_name("3"), tag_with_name("4")],
90
+ tag_with_name("3") => [tag_with_name("1"), tag_with_name("3")],
91
+ tag_with_name("1") => [nil, tag_with_name("1")]
92
+ }
93
+ end
94
+
95
+ it_behaves_like "a section mapping"
96
+ end
97
+
98
+ context "with no constraints" do
99
+ it_behaves_like "a full changelog"
100
+ end
101
+
102
+ context "with since only" do
103
+ let(:options) { { since_tag: "6" } }
104
+ let(:expected_mapping) do
105
+ {
106
+ tag_with_name("8") => [tag_with_name("7"), tag_with_name("8")],
107
+ tag_with_name("7") => [tag_with_name("6"), tag_with_name("7")]
108
+ }
109
+ end
110
+
111
+ it_behaves_like "a section mapping"
112
+ end
113
+
114
+ context "with due only" do
115
+ let(:options) { { due_tag: "4" } }
116
+ let(:expected_mapping) do
117
+ {
118
+ tag_with_name("3") => [tag_with_name("2"), tag_with_name("3")],
119
+ tag_with_name("2") => [tag_with_name("1"), tag_with_name("2")],
120
+ tag_with_name("1") => [nil, tag_with_name("1")]
121
+ }
122
+ end
123
+
124
+ it_behaves_like "a section mapping"
125
+ end
126
+
127
+ context "with since and due" do
128
+ let(:options) { { since_tag: "2", due_tag: "5" } }
129
+ let(:expected_mapping) do
130
+ {
131
+ tag_with_name("4") => [tag_with_name("3"), tag_with_name("4")],
132
+ tag_with_name("3") => [tag_with_name("2"), tag_with_name("3")]
133
+ }
134
+ end
135
+
136
+ it_behaves_like "a section mapping"
137
+ end
138
+
139
+ context "with excluded tags" do
140
+ context "as a list of strings" do
141
+ let(:options) { { exclude_tags: %w[2 5 7] } }
142
+
143
+ it_behaves_like "a changelog with some exclusions"
144
+ end
145
+
146
+ context "as a regex" do
147
+ let(:options) { { exclude_tags: /[257]/ } }
148
+
149
+ it_behaves_like "a changelog with some exclusions"
150
+ end
151
+
152
+ context "as a regex string" do
153
+ let(:options) { { exclude_tags_regex: "[257]" } }
154
+
155
+ it_behaves_like "a changelog with some exclusions"
156
+ end
157
+ end
158
+ end
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
+
176
+ describe "#filter_excluded_tags" do
177
+ subject { generator.filter_excluded_tags(tags_from_strings(%w[1 2 3])) }
178
+
179
+ context "with matching string" do
180
+ let(:generator) { GitHubChangelogGenerator::Generator.new(exclude_tags: %w[3]) }
181
+ it { is_expected.to be_a Array }
182
+ it { is_expected.to match_array(tags_from_strings(%w[1 2])) }
183
+ end
184
+
185
+ context "with non-matching string" do
186
+ let(:generator) { GitHubChangelogGenerator::Generator.new(exclude_tags: %w[invalid tags]) }
187
+ it { is_expected.to be_a Array }
188
+ it { is_expected.to match_array(tags_from_strings(%w[1 2 3])) }
189
+ end
190
+
191
+ context "with matching regex" do
192
+ let(:generator) { GitHubChangelogGenerator::Generator.new(exclude_tags: /[23]/) }
193
+ it { is_expected.to be_a Array }
194
+ it { is_expected.to match_array(tags_from_strings(%w[1])) }
195
+ end
196
+
197
+ context "with non-matching regex" do
198
+ let(:generator) { GitHubChangelogGenerator::Generator.new(exclude_tags: /[abc]/) }
199
+ it { is_expected.to be_a Array }
200
+ it { is_expected.to match_array(tags_from_strings(%w[1 2 3])) }
201
+ end
202
+ end
203
+
204
+ describe "#filter_excluded_tags_regex" do
205
+ subject { generator.filter_excluded_tags(tags_from_strings(%w[1 2 3])) }
206
+
207
+ context "with matching regex" do
208
+ let(:generator) { GitHubChangelogGenerator::Generator.new(exclude_tags_regex: "[23]") }
209
+ it { is_expected.to be_a Array }
210
+ it { is_expected.to match_array(tags_from_strings(%w[1])) }
211
+ end
212
+
213
+ context "with non-matching regex" do
214
+ let(:generator) { GitHubChangelogGenerator::Generator.new(exclude_tags_regex: "[45]") }
215
+ it { is_expected.to be_a Array }
216
+ it { is_expected.to match_array(tags_from_strings(%w[1 2 3])) }
217
+ end
218
+ end
219
+
220
+ describe "#filter_since_tag" do
221
+ context "with filled array" do
222
+ subject { generator.filter_since_tag(tags_from_strings(%w[1 2 3])) }
223
+
224
+ context "with valid since tag" do
225
+ let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "2") }
226
+ it { is_expected.to be_a Array }
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
233
+ end
234
+
235
+ context "with invalid since tag" do
236
+ let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "Invalid tag") }
237
+ it { expect { subject }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError) }
238
+ end
239
+ end
240
+
241
+ context "with empty array" do
242
+ subject { generator.filter_since_tag(tags_from_strings(%w[])) }
243
+
244
+ context "with invalid since tag" do
245
+ let(:generator) { GitHubChangelogGenerator::Generator.new(since_tag: "Invalid tag") }
246
+ it { expect { subject }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError) }
247
+ end
248
+ end
249
+ end
250
+
251
+ describe "#filter_due_tag" do
252
+ context "with filled array" do
253
+ subject { generator.filter_due_tag(tags_from_strings(%w[1 2 3])) }
254
+
255
+ context "with valid due tag" do
256
+ let(:generator) { GitHubChangelogGenerator::Generator.new(due_tag: "2") }
257
+ it { is_expected.to be_a Array }
258
+ it { is_expected.to match_array(tags_from_strings(%w[3])) }
259
+ end
260
+
261
+ context "with invalid due tag" do
262
+ let(:generator) { GitHubChangelogGenerator::Generator.new(due_tag: "Invalid tag") }
263
+ it { expect { subject }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError) }
264
+ end
265
+ end
266
+
267
+ context "with empty array" do
268
+ subject { generator.filter_due_tag(tags_from_strings(%w[])) }
269
+
270
+ context "with invalid due tag" do
271
+ let(:generator) { GitHubChangelogGenerator::Generator.new(due_tag: "Invalid tag") }
272
+ it { expect { subject }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError) }
273
+ end
274
+ end
275
+ end
276
+
277
+ describe "#get_time_of_tag" do
278
+ current_time = Time.now
279
+ before(:all) { @generator = GitHubChangelogGenerator::Generator.new }
280
+ context "run with nil parameter" do
281
+ it "should raise ChangelogGeneratorError" do
282
+ expect { @generator.get_time_of_tag nil }.to raise_error(GitHubChangelogGenerator::ChangelogGeneratorError)
283
+ end
284
+ end
285
+ context "fetch already filled tag" do
286
+ before { @generator.instance_variable_set :@tag_times_hash, "valid_tag" => current_time }
287
+ subject { @generator.get_time_of_tag tag_with_name("valid_tag") }
288
+ it { is_expected.to be_a_kind_of(Time) }
289
+ it { is_expected.to eq(current_time) }
290
+ end
291
+ context "fetch not filled tag" do
292
+ before do
293
+ mock = double("fake fetcher")
294
+ allow(mock).to receive_messages(fetch_date_of_tag: current_time)
295
+ @generator.instance_variable_set :@fetcher, mock
296
+ end
297
+ subject do
298
+ of_tag = @generator.get_time_of_tag(tag_with_name("valid_tag"))
299
+ of_tag
300
+ end
301
+ it { is_expected.to be_a_kind_of(Time) }
302
+ it { is_expected.to eq(current_time) }
303
+ end
304
+ end
305
+
306
+ describe "#sort_tags_by_date" do
307
+ let(:time1) { Time.now }
308
+ let(:time2) { Time.now }
309
+ let(:time3) { Time.now }
310
+
311
+ before(:all) do
312
+ @generator = GitHubChangelogGenerator::Generator.new
313
+ end
314
+
315
+ before do
316
+ @generator.instance_variable_set(:@tag_times_hash, "valid_tag1" => time1,
317
+ "valid_tag2" => time2,
318
+ "valid_tag3" => time3)
319
+ end
320
+
321
+ subject do
322
+ @generator.sort_tags_by_date(tags)
323
+ end
324
+ context "sort unsorted tags" do
325
+ let(:tags) { tags_from_strings %w[valid_tag1 valid_tag2 valid_tag3] }
326
+
327
+ it { is_expected.to be_a_kind_of(Array) }
328
+ it { is_expected.to match_array(tags.reverse!) }
329
+ end
330
+ context "sort sorted tags" do
331
+ let(:tags) { tags_from_strings %w[valid_tag3 valid_tag2 valid_tag1] }
332
+
333
+ it { is_expected.to be_a_kind_of(Array) }
334
+ it { is_expected.to match_array(tags) }
335
+ end
336
+ end
337
+ end
@@ -0,0 +1,43 @@
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
+
34
+ describe "#normalize_body" do
35
+ context "it should remove CR" do
36
+ let(:body) { "Some content from GitHub\r\n\r\nUser is describing something" }
37
+ it "returns a cleaned body" do
38
+ expect(section.send(:normalize_body, body)).to eq "Some content from GitHub\n\nUser is describing something"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end