renogen 1.2.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +119 -26
  3. data/lib/renogen/change_log.rb +1 -0
  4. data/lib/renogen/change_log/item.rb +6 -4
  5. data/lib/renogen/change_log/model.rb +9 -0
  6. data/lib/renogen/change_log/validator.rb +61 -0
  7. data/lib/renogen/change_log/writer.rb +35 -3
  8. data/lib/renogen/cli.rb +7 -4
  9. data/lib/renogen/config.rb +16 -15
  10. data/lib/renogen/exceptions.rb +5 -0
  11. data/lib/renogen/exceptions/invalid_item_found.rb +32 -0
  12. data/lib/renogen/exceptions/yaml_file_blank.rb +21 -0
  13. data/lib/renogen/exceptions/yaml_file_invalid.rb +20 -0
  14. data/lib/renogen/extraction_stratagies.rb +0 -2
  15. data/lib/renogen/extraction_stratagies/yaml_file.rb +0 -1
  16. data/lib/renogen/extraction_stratagies/yaml_file/parser.rb +5 -4
  17. data/lib/renogen/extraction_stratagies/yaml_file/reader.rb +20 -11
  18. data/lib/renogen/formatters.rb +2 -0
  19. data/lib/renogen/formatters/base.rb +14 -4
  20. data/lib/renogen/formatters/csv.rb +42 -0
  21. data/lib/renogen/formatters/html.rb +1 -1
  22. data/lib/renogen/formatters/markdown.rb +2 -2
  23. data/lib/renogen/formatters/markdown_table.rb +58 -0
  24. data/lib/renogen/generator.rb +8 -1
  25. data/lib/renogen/version.rb +1 -1
  26. data/lib/renogen/writers/csv.rb +23 -0
  27. data/spec/lib/renogen/change_log/item_spec.rb +1 -1
  28. data/spec/lib/renogen/change_log/model_spec.rb +1 -1
  29. data/spec/lib/renogen/change_log/validator_spec.rb +38 -0
  30. data/spec/lib/renogen/change_log/writer_spec.rb +199 -2
  31. data/spec/lib/renogen/config_spec.rb +7 -2
  32. data/spec/lib/renogen/exceptions/invalid_item_found_spec.rb +35 -0
  33. data/spec/lib/renogen/exceptions/stratagy_not_found_spec.rb +2 -1
  34. data/spec/lib/renogen/{extraction_stratagies/yaml_file/exceptions → exceptions}/yaml_file_blank_spec.rb +1 -1
  35. data/spec/lib/renogen/exceptions/yaml_file_invalid_spec.rb +12 -0
  36. data/spec/lib/renogen/extraction_stratagies/yaml_file/parser_spec.rb +3 -3
  37. data/spec/lib/renogen/extraction_stratagies/yaml_file/reader_spec.rb +11 -5
  38. data/spec/lib/renogen/formatters/base_spec.rb +8 -8
  39. data/spec/lib/renogen/formatters/csv_spec.rb +49 -0
  40. data/spec/lib/renogen/formatters/html_spec.rb +1 -1
  41. data/spec/lib/renogen/formatters/markdown_spec.rb +2 -2
  42. data/spec/spec_helper.rb +5 -0
  43. data/spec/support/renogen_helper.rb +9 -0
  44. metadata +17 -8
  45. data/lib/renogen/extraction_stratagies/yaml_file/exceptions.rb +0 -12
  46. data/lib/renogen/extraction_stratagies/yaml_file/exceptions/yaml_file_blank.rb +0 -25
@@ -1,3 +1,3 @@
1
1
  module Renogen
2
- VERSION='1.2.0'.freeze # :nodoc:
2
+ VERSION = '1.4.1'.freeze # :nodoc:
3
3
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Renogen
4
+ module Writers
5
+ # Writes out the change log in CSV format
6
+ class Csv < Base
7
+ register :csv
8
+
9
+ def write!(changelog)
10
+ puts formatter.write_headings(changelog)
11
+ output_files(changelog)
12
+ end
13
+
14
+ private
15
+
16
+ def output_files(changelog)
17
+ changelog.files.each do |file|
18
+ puts formatter.write_file(file, changelog)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Renogen::ChangeLog::Item do
4
4
  let(:change) { Array.new }
5
- subject { described_class.new('foo', change) }
5
+ subject { described_class.new(1, 'foo', change) }
6
6
 
7
7
  describe '#to_s' do
8
8
  context "when change type is nil" do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Renogen::ChangeLog::Model do
4
- let(:change_item) { Renogen::ChangeLog::Item.new('foo', 'bar') }
4
+ let(:change_item) { Renogen::ChangeLog::Item.new(1, 'foo', 'bar') }
5
5
 
6
6
  describe '#groups' do
7
7
  it 'returns an empty hash when no changes' do
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Renogen::ChangeLog::Validator do
6
+ let(:change_log) { Renogen::ChangeLog::Model.new }
7
+ let(:validations) { { 'foo' => %w(bar baz) } }
8
+
9
+ subject { described_class.new(double('Formatter', options: { 'allowed_values' => validations })) }
10
+
11
+ before(:each) { change_log.add_change(Renogen::ChangeLog::Item.new(1, 'foo', 'bar')) }
12
+
13
+ describe '#validate!' do
14
+ context 'when no validations are available' do
15
+ let(:validations) { nil }
16
+
17
+ it 'successfully passes the validation process' do
18
+ expect { subject.validate!(change_log) }.to_not raise_error
19
+ subject.validate!(change_log)
20
+ end
21
+ end
22
+
23
+ context 'when validation is successful' do
24
+ it 'successfully passes the validation process' do
25
+ expect { subject.validate!(change_log) }.to_not raise_error
26
+ subject.validate!(change_log)
27
+ end
28
+ end
29
+
30
+ context 'when validation has failed' do
31
+ let(:validations) { { 'foo' => ['baz'] } }
32
+
33
+ it 'fails validation' do
34
+ expect { subject.validate!(change_log) }.to raise_error(Renogen::Exceptions::InvalidItemFound)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,8 +1,205 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Renogen::ChangeLog::Writer do
4
-
5
6
  describe '#write!' do
7
+ shared_examples 'a valid output format' do
8
+ let(:changelog) do
9
+ Renogen::ChangeLog::Model.new(
10
+ version: 'test',
11
+ date: Date.new(2020, 7, 8)
12
+ )
13
+ end
14
+
15
+ let(:changes) do
16
+ [
17
+ renogen_change(1, 'Group 1', 'This is a Group 1 change'),
18
+ renogen_change(1, 'Group 2', 'This is a Group 2 change')
19
+ ]
20
+ end
21
+
22
+ subject { Renogen::ChangeLog::Writer.new(formatter) }
23
+
24
+ before do
25
+ changes.each { |c| changelog.add_change(c) }
26
+ $stdout = StringIO.new
27
+ end
28
+
29
+ after do
30
+ $stdout = STDOUT
31
+ end
32
+
33
+ it 'writes all lines' do
34
+ subject.write!(changelog)
35
+ $stdout.rewind
36
+ expected_output.split("\n").each do |line|
37
+ expect($stdout.gets.strip).to eq(line)
38
+ end
39
+
40
+ # read remaining output and check we reached the end
41
+ expect($stdout.read.gsub("\n", '')).to be_empty
42
+ end
43
+ end
44
+
45
+ context 'when formatter is CSV' do
46
+ let(:formatter) { Renogen::Formatters::Csv.new }
47
+ let(:expected_output) do
48
+ <<~EOS
49
+ Group 1,Group 2
50
+ This is a Group 1 change,This is a Group 2 change
51
+ EOS
52
+ end
53
+
54
+ it_behaves_like 'a valid output format'
55
+
56
+ context 'when changes contain commas' do
57
+ it_behaves_like 'a valid output format' do
58
+ let(:changes) do
59
+ [
60
+ renogen_change(1, 'Group 1', 'This,is,a,Group 1,change'),
61
+ renogen_change(1, 'Group 2', 'This is a Group 2 change')
62
+ ]
63
+ end
64
+
65
+ let(:expected_output) do
66
+ <<~EOS
67
+ Group 1,Group 2
68
+ "This,is,a,Group 1,change",This is a Group 2 change
69
+ EOS
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ context 'when formatter is HTML' do
76
+ let(:formatter) { Renogen::Formatters::Html.new }
77
+ let(:expected_output) do
78
+ <<~EOS
79
+ <html>
80
+ <h1>test (2020-07-08)</h1>
81
+ <h2>Group 1</h2>
82
+ <ul>
83
+ <li>This is a Group 1 change
84
+ </li>
85
+ </ul>
86
+ <h2>Group 2</h2>
87
+ <ul>
88
+ <li>This is a Group 2 change
89
+ </li>
90
+ </ul>
91
+ </html>
92
+ EOS
93
+ end
94
+
95
+ it_behaves_like 'a valid output format'
96
+ end
97
+
98
+ context 'when formatter is Markdown' do
99
+ let(:formatter) { Renogen::Formatters::Markdown.new }
100
+ let(:expected_output) do
101
+ <<~EOS
102
+ # test (2020-07-08)
103
+
104
+ ## Group 1
105
+
106
+ * This is a Group 1 change
107
+
108
+ ## Group 2
109
+
110
+ * This is a Group 2 change
111
+ EOS
112
+ end
113
+
114
+ it_behaves_like 'a valid output format'
115
+ end
116
+
117
+ context 'when formatter is MarkdownTable' do
118
+ let(:formatter) { Renogen::Formatters::MarkdownTable.new }
119
+
120
+ let(:expected_output) do
121
+ <<~EOS
122
+ # test (2020-07-08)
123
+
124
+ | Group 1 | Group 2 |
125
+ | - | - |
126
+ | This is a Group 1 change<br> | This is a Group 2 change<br> |
127
+ EOS
128
+ end
129
+
130
+ it_behaves_like 'a valid output format'
131
+ end
132
+
133
+ context 'when formatter is PlainText' do
134
+ let(:formatter) { Renogen::Formatters::PlainText.new }
135
+ let(:expected_output) do
136
+ <<~EOS
137
+ test (2020-07-08)
138
+
139
+ Group 1
140
+ - This is a Group 1 change
141
+
142
+ Group 2
143
+ - This is a Group 2 change
144
+ EOS
145
+ end
146
+
147
+ it_behaves_like 'a valid output format'
148
+ end
149
+
150
+ describe 'duplicates' do
151
+ let(:formatter) { Renogen::Formatters::PlainText.new }
152
+ let(:changes_with_duplicates) do
153
+ [
154
+ renogen_change(1, 'Group 1', 'This is a Group 1 change'),
155
+ renogen_change(1, 'Group 2', 'This is a Group 2 change'),
156
+ renogen_change(2, 'Group 1', 'This is a Group 1 change'),
157
+ renogen_change(2, 'Group 2', 'This is a Group 2 change')
158
+ ]
159
+ end
160
+
161
+ context 'when remove duplicates is false in config (default)' do
162
+ it_behaves_like 'a valid output format' do
163
+ let(:changes) { changes_with_duplicates }
164
+
165
+ let(:expected_output) do
166
+ <<~EOS
167
+ test (2020-07-08)
168
+
169
+ Group 1
170
+ - This is a Group 1 change
171
+ - This is a Group 1 change
172
+
173
+ Group 2
174
+ - This is a Group 2 change
175
+ - This is a Group 2 change
176
+ EOS
177
+ end
178
+ end
179
+ end
180
+
181
+ context 'when remove duplicates is true in config' do
182
+ before do
183
+ allow(Renogen::Config.instance)
184
+ .to receive(:remove_duplicates).and_return(true)
185
+ end
186
+
187
+ it_behaves_like 'a valid output format' do
188
+ let(:changes) { changes_with_duplicates }
189
+
190
+ let(:expected_output) do
191
+ <<~EOS
192
+ test (2020-07-08)
193
+
194
+ Group 1
195
+ - This is a Group 1 change
196
+
197
+ Group 2
198
+ - This is a Group 2 change
199
+ EOS
200
+ end
201
+ end
202
+ end
203
+ end
6
204
  end
7
205
  end
8
-
@@ -1,19 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Renogen::Config do
4
-
5
6
  subject { described_class.instance }
6
7
 
7
8
  describe '#configure' do
8
9
  before :each do
9
10
  described_class.configure do |config|
10
11
  config.single_line_format = 'bar'
12
+ config.validations = ['test']
11
13
  end
12
14
  end
13
15
 
14
16
  it 'can set value' do
15
17
  expect(subject.single_line_format).to eql 'bar'
16
18
  end
17
- end
18
19
 
20
+ it 'sets the validations value' do
21
+ expect(subject.validations).to eql ['test']
22
+ end
23
+ end
19
24
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Renogen::Exceptions::InvalidItemFound do
6
+ subject { described_class.new(invalid_items) }
7
+
8
+ describe '#message' do
9
+ context 'valid_values is an array' do
10
+ let(:invalid_items) do
11
+ [
12
+ { group_name: 'Product', invalid_value: 'Foo', valid_values: %w(Bar Baz) },
13
+ { group_name: 'Country', invalid_value: 'LL', valid_values: %w(UK IE) }
14
+ ]
15
+ end
16
+ let(:expected_error) do
17
+ "Invalid items:\nGroup: Product, Content: Foo, Valid Values: [\"Bar\", \"Baz\"]" \
18
+ "\nGroup: Country, Content: LL, Valid Values: [\"UK\", \"IE\"]"
19
+ end
20
+
21
+ it 'returns a user friendly error message' do
22
+ expect(subject.message).to eql expected_error
23
+ end
24
+ end
25
+
26
+ context 'valid_values is a RegExp' do
27
+ let(:invalid_items) { [{ group_name: 'Product', invalid_value: 'Foo', valid_values: /\b(Bar|Baz)\b/ }] }
28
+ let(:expected_error) { "Invalid items:\nGroup: Product, Content: Foo, Pattern: #{/\b(Bar|Baz)\b/.inspect}" }
29
+
30
+ it 'returns a user friendly error message' do
31
+ expect(subject.message).to eql expected_error
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Renogen::Exceptions::StratagyNotFound do
@@ -8,6 +10,5 @@ describe Renogen::Exceptions::StratagyNotFound do
8
10
  it 'returns friendly error message' do
9
11
  expect(subject.message).to eql "Error: Stratagy type '#{name}' not found"
10
12
  end
11
-
12
13
  end
13
14
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Renogen::ExtractionStratagies::YamlFile::Exceptions::YamlFileBlank do
3
+ describe Renogen::Exceptions::YamlFileBlank do
4
4
  let(:name) { 'foobar' }
5
5
  subject { described_class.new(name) }
6
6
 
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Renogen::Exceptions::YamlFileInvalid do
4
+ let(:name) { 'foobar' }
5
+ subject { described_class.new(name) }
6
+
7
+ describe '#message' do
8
+ it 'returns friendly error message' do
9
+ expect(subject.message).to eql "Error: File contents invalid '#{name}'"
10
+ end
11
+ end
12
+ end
@@ -6,13 +6,13 @@ describe Renogen::ExtractionStratagies::YamlFile::Parser do
6
6
  describe '#parse!' do
7
7
  before :each do
8
8
  yaml_file_reader = double(Renogen::ExtractionStratagies::YamlFile::Reader)
9
- allow(yaml_file_reader).to receive(:each_yaml_file).and_yield(file_contents)
9
+ allow(yaml_file_reader).to receive(:each_yaml_file).and_yield(file_contents, 1)
10
10
  allow(Renogen::ExtractionStratagies::YamlFile::Reader).to receive(:new).and_return(yaml_file_reader)
11
11
  end
12
12
 
13
13
  it 'extracts contents from file' do
14
- changelog_item = Renogen::ChangeLog::Item.new('Foo', 'Bar')
15
- allow(Renogen::ChangeLog::Item).to receive(:new).with('Foo', 'Bar').and_return changelog_item
14
+ changelog_item = Renogen::ChangeLog::Item.new(1, 'Foo', 'Bar')
15
+ allow(Renogen::ChangeLog::Item).to receive(:new).with(1, 'Foo', 'Bar').and_return changelog_item
16
16
 
17
17
  changelog = subject.parse!
18
18
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
  require 'json'
3
5
 
@@ -6,15 +8,19 @@ describe Renogen::ExtractionStratagies::YamlFile::Reader do
6
8
  subject { described_class.new(directory_path) }
7
9
 
8
10
  describe '#each_yaml_file' do
9
- let(:file_contents) { { 'Foo' => 'Bar' }.to_json }
11
+ let(:file_contents) { { 'Foo' => 'bar' }.to_json }
10
12
 
11
- before :each do
12
- allow(Dir).to receive(:glob).with([File.join(directory_path, 'next', "*.yml")]).and_return(['foo_file'])
13
+ it 'yields each yaml file within given directory' do
14
+ allow(Dir).to receive(:glob).with([File.join(directory_path, 'next', '*.yml')]).and_return(['foo_file'])
13
15
  allow(YAML).to receive(:load_file).with('foo_file').and_return(file_contents)
16
+ expect { |b| subject.each_yaml_file(&b) }.to yield_with_args(file_contents, 0)
14
17
  end
15
18
 
16
- it 'yields each yaml file within given directory' do
17
- expect{ |b| subject.each_yaml_file(&b) }.to yield_with_args(file_contents)
19
+ it 'throws invalid yaml file when missing quotes' do
20
+ allow(subject).to receive(:change_directories).and_return(%w(foo bar))
21
+ foo = Psych::SyntaxError.new('a', 1, 2, 'd', 'e', 'f')
22
+ allow(YAML).to receive(:load_file).and_raise(foo)
23
+ expect { subject.each_yaml_file }.to raise_error(Renogen::Exceptions::YamlFileInvalid)
18
24
  end
19
25
  end
20
26
  end