renogen 1.2.1 → 1.3.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.
- checksums.yaml +5 -5
- data/README.md +112 -27
- data/lib/renogen/change_log.rb +1 -0
- data/lib/renogen/change_log/item.rb +6 -4
- data/lib/renogen/change_log/model.rb +9 -0
- data/lib/renogen/change_log/validator.rb +61 -0
- data/lib/renogen/change_log/writer.rb +22 -2
- data/lib/renogen/cli.rb +6 -4
- data/lib/renogen/config.rb +15 -15
- data/lib/renogen/exceptions.rb +5 -0
- data/lib/renogen/exceptions/invalid_item_found.rb +32 -0
- data/lib/renogen/exceptions/yaml_file_blank.rb +21 -0
- data/lib/renogen/exceptions/yaml_file_invalid.rb +20 -0
- data/lib/renogen/extraction_stratagies.rb +0 -2
- data/lib/renogen/extraction_stratagies/yaml_file.rb +0 -1
- data/lib/renogen/extraction_stratagies/yaml_file/parser.rb +5 -4
- data/lib/renogen/extraction_stratagies/yaml_file/reader.rb +20 -11
- data/lib/renogen/formatters.rb +2 -0
- data/lib/renogen/formatters/base.rb +14 -4
- data/lib/renogen/formatters/csv.rb +41 -0
- data/lib/renogen/formatters/markdown_table.rb +58 -0
- data/lib/renogen/generator.rb +8 -1
- data/lib/renogen/version.rb +1 -1
- data/lib/renogen/writers/csv.rb +23 -0
- data/spec/lib/renogen/change_log/item_spec.rb +1 -1
- data/spec/lib/renogen/change_log/model_spec.rb +1 -1
- data/spec/lib/renogen/change_log/validator_spec.rb +38 -0
- data/spec/lib/renogen/config_spec.rb +7 -2
- data/spec/lib/renogen/exceptions/invalid_item_found_spec.rb +35 -0
- data/spec/lib/renogen/exceptions/stratagy_not_found_spec.rb +2 -1
- data/spec/lib/renogen/{extraction_stratagies/yaml_file/exceptions → exceptions}/yaml_file_blank_spec.rb +1 -1
- data/spec/lib/renogen/exceptions/yaml_file_invalid_spec.rb +12 -0
- data/spec/lib/renogen/extraction_stratagies/yaml_file/parser_spec.rb +3 -3
- data/spec/lib/renogen/extraction_stratagies/yaml_file/reader_spec.rb +11 -5
- data/spec/lib/renogen/formatters/base_spec.rb +8 -8
- data/spec/lib/renogen/formatters/csv_spec.rb +49 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/renogen_helper.rb +9 -0
- metadata +15 -6
- data/lib/renogen/extraction_stratagies/yaml_file/exceptions.rb +0 -12
- data/lib/renogen/extraction_stratagies/yaml_file/exceptions/yaml_file_blank.rb +0 -25
- data/spec/lib/renogen/change_log/writer_spec.rb +0 -8
data/lib/renogen/exceptions.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Renogen
|
2
4
|
# Custom exceptions throw by the libary
|
3
5
|
module Exceptions
|
4
6
|
require_relative 'exceptions/base'
|
5
7
|
require_relative 'exceptions/stratagy_not_found'
|
8
|
+
require_relative 'exceptions/invalid_item_found'
|
9
|
+
require_relative 'exceptions/yaml_file_blank'
|
10
|
+
require_relative 'exceptions/yaml_file_invalid'
|
6
11
|
end
|
7
12
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renogen
|
4
|
+
module Exceptions
|
5
|
+
# Raised when change log contains invalid items.
|
6
|
+
class InvalidItemFound < Base
|
7
|
+
attr_reader :invalid_items
|
8
|
+
|
9
|
+
def initialize(invalid_items)
|
10
|
+
@invalid_items = invalid_items
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
# Friendly error message
|
15
|
+
#
|
16
|
+
# @return [String]
|
17
|
+
def message
|
18
|
+
messages = ['Invalid items:']
|
19
|
+
invalid_items.each do |item|
|
20
|
+
invalid_value = item[:invalid_value]
|
21
|
+
|
22
|
+
messages << if item[:valid_values].is_a?(Regexp)
|
23
|
+
"Group: #{item[:group_name]}, Content: #{invalid_value}, Pattern: #{item[:valid_values].inspect}"
|
24
|
+
else
|
25
|
+
"Group: #{item[:group_name]}, Content: #{invalid_value}, Valid Values: #{item[:valid_values]}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
messages.join("\n")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Renogen
|
2
|
+
module Exceptions
|
3
|
+
# This is raised when a yaml file change is found but has not contents
|
4
|
+
class YamlFileBlank < Renogen::Exceptions::Base
|
5
|
+
attr_reader :file_path
|
6
|
+
|
7
|
+
def initialize(file_path)
|
8
|
+
@file_path = file_path
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# Friendly error message
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
def message
|
16
|
+
"Error: File contents blank '#{file_path}'"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Renogen
|
2
|
+
module Exceptions
|
3
|
+
# This is raised when a yaml file change is found but has invalid contents
|
4
|
+
class YamlFileInvalid < Renogen::Exceptions::Base
|
5
|
+
attr_reader :file_path
|
6
|
+
|
7
|
+
def initialize(file_path)
|
8
|
+
@file_path = file_path
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# Friendly error message
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
def message
|
16
|
+
"Error: File contents invalid '#{file_path}'"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -13,8 +13,8 @@ module Renogen
|
|
13
13
|
|
14
14
|
# @return [ChangeLog::Model]
|
15
15
|
def parse!
|
16
|
-
yaml_file_reader.each_yaml_file do |file|
|
17
|
-
parse_file(file)
|
16
|
+
yaml_file_reader.each_yaml_file do |file, index|
|
17
|
+
parse_file(index, file)
|
18
18
|
end
|
19
19
|
changelog
|
20
20
|
end
|
@@ -23,9 +23,10 @@ module Renogen
|
|
23
23
|
|
24
24
|
attr_reader :yaml_file_reader
|
25
25
|
|
26
|
-
|
26
|
+
# @param [Hash] data
|
27
|
+
def parse_file(id, file)
|
27
28
|
file.each do |group_name, content|
|
28
|
-
changelog.add_change(ChangeLog::Item.new(group_name, content))
|
29
|
+
changelog.add_change(ChangeLog::Item.new(id, group_name, content))
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'yaml'
|
2
4
|
|
3
5
|
module Renogen
|
@@ -7,23 +9,28 @@ module Renogen
|
|
7
9
|
class Reader
|
8
10
|
attr_accessor :directory_path, :legacy_version
|
9
11
|
|
10
|
-
def initialize(directory_path, options={})
|
12
|
+
def initialize(directory_path, options = {})
|
11
13
|
@legacy_version = options['legacy_version']
|
12
14
|
@directory_path = directory_path
|
13
15
|
@directory_path ||= './change_log/'
|
14
16
|
end
|
15
17
|
|
16
18
|
# Iterates thorugh each change file and yields the contents.
|
17
|
-
#
|
18
|
-
# an exception is thrown if the contents are blank
|
19
|
+
#
|
20
|
+
# an exception is thrown if the contents are blank or invalid
|
19
21
|
#
|
20
22
|
# @yield [Hash] yaml_file
|
21
23
|
def each_yaml_file
|
22
|
-
|
24
|
+
path = ''
|
25
|
+
change_directories.each_with_index do |file_path, i|
|
26
|
+
path = file_path
|
23
27
|
content = ::YAML.load_file(file_path)
|
24
|
-
raise Exceptions::YamlFileBlank
|
25
|
-
|
28
|
+
raise Exceptions::YamlFileBlank, file_path unless content
|
29
|
+
|
30
|
+
yield content, i
|
26
31
|
end
|
32
|
+
rescue Psych::SyntaxError
|
33
|
+
raise Exceptions::YamlFileInvalid, path
|
27
34
|
end
|
28
35
|
|
29
36
|
private
|
@@ -31,20 +38,22 @@ module Renogen
|
|
31
38
|
# @return [Array]
|
32
39
|
def change_directories
|
33
40
|
upgrade_versions = legacy_versions.map do |path|
|
34
|
-
File.join(path,
|
41
|
+
File.join(path, '*.yml')
|
35
42
|
end
|
36
|
-
upgrade_versions << File.join(directory_path, 'next',
|
43
|
+
upgrade_versions << File.join(directory_path, 'next', '*.yml')
|
37
44
|
|
38
45
|
Dir.glob(upgrade_versions)
|
39
46
|
end
|
40
47
|
|
41
|
-
# @return [Array]
|
48
|
+
# @return [Array]
|
42
49
|
def legacy_versions
|
43
50
|
return [] unless legacy_version
|
44
|
-
|
51
|
+
|
52
|
+
legacy_version.gsub!('v', '')
|
45
53
|
Dir.glob(File.join(directory_path, '*')).select do |dir|
|
46
|
-
dir = dir.split('/').last.gsub('v','').gsub('_','.')
|
54
|
+
dir = dir.split('/').last.gsub('v', '').gsub('_', '.')
|
47
55
|
next if dir == 'next'
|
56
|
+
|
48
57
|
Gem::Version.new(dir) > Gem::Version.new(legacy_version)
|
49
58
|
end
|
50
59
|
end
|
data/lib/renogen/formatters.rb
CHANGED
@@ -37,7 +37,9 @@ module Renogen
|
|
37
37
|
end
|
38
38
|
|
39
39
|
require_relative 'formatters/base'
|
40
|
+
require_relative 'formatters/csv'
|
40
41
|
require_relative 'formatters/plain_text'
|
41
42
|
require_relative 'formatters/markdown'
|
43
|
+
require_relative 'formatters/markdown_table'
|
42
44
|
require_relative 'formatters/html'
|
43
45
|
end
|
@@ -1,9 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Renogen
|
2
4
|
module Formatters
|
3
|
-
# Implements a template pattern that forces the implemention of required
|
5
|
+
# Implements a template pattern that forces the implemention of required
|
4
6
|
# methods in sub classes
|
5
7
|
class Base
|
6
|
-
|
8
|
+
attr_reader :options
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
# Switch to determine if the formatter is in table format(instead of group format)
|
15
|
+
#
|
16
|
+
# return [Boolean] (default: false)
|
17
|
+
def table_formatter?
|
18
|
+
false # for backward compatibility
|
7
19
|
end
|
8
20
|
|
9
21
|
# Adds class with identifier to formatters
|
@@ -29,7 +41,6 @@ module Renogen
|
|
29
41
|
# @param header [String]
|
30
42
|
# @raise NotImplementedError
|
31
43
|
def write_header(header)
|
32
|
-
raise NotImplementedError
|
33
44
|
end
|
34
45
|
|
35
46
|
# Outputs a line or block as a header for a group.
|
@@ -39,7 +50,6 @@ module Renogen
|
|
39
50
|
# @param group [String]
|
40
51
|
# @raise NotImplementedError
|
41
52
|
def write_group(group)
|
42
|
-
raise NotImplementedError
|
43
53
|
end
|
44
54
|
|
45
55
|
# Outputs a line or block of text appearing after a group.
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renogen
|
4
|
+
module Formatters
|
5
|
+
# For formatting a change into CSV output
|
6
|
+
class Csv < Base
|
7
|
+
register :csv
|
8
|
+
|
9
|
+
attr_reader :headings
|
10
|
+
|
11
|
+
def table_formatter?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def write_header(header)
|
16
|
+
"#{header}\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
def write_change(ticket)
|
20
|
+
headings.map do |header|
|
21
|
+
raw_line = ticket[header]
|
22
|
+
next if raw_line.nil?
|
23
|
+
|
24
|
+
parsed_line = raw_line.is_a?(Array) ? raw_line.join(',') : raw_line
|
25
|
+
parsed_line.gsub!("\n", '\n') if parsed_line.include?("\n")
|
26
|
+
|
27
|
+
if parsed_line.include?(',')
|
28
|
+
"\"#{parsed_line}\""
|
29
|
+
else
|
30
|
+
parsed_line
|
31
|
+
end
|
32
|
+
end.join(',')
|
33
|
+
end
|
34
|
+
|
35
|
+
def header(changelog)
|
36
|
+
@headings = changelog.groups.keys
|
37
|
+
@headings.join(',')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Renogen
|
2
|
+
module Formatters
|
3
|
+
# For formatting a change into markdown format
|
4
|
+
class MarkdownTable < Markdown
|
5
|
+
register :markdown_table
|
6
|
+
register :md_table
|
7
|
+
|
8
|
+
attr_reader :headings
|
9
|
+
|
10
|
+
def table_formatter?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
# Generate header
|
15
|
+
#
|
16
|
+
# @param changelog [Renogen::ChangeLog::Model]
|
17
|
+
#
|
18
|
+
# return [String]
|
19
|
+
def header(changelog)
|
20
|
+
@headings = changelog.groups.keys
|
21
|
+
[
|
22
|
+
"# #{changelog.version} (#{changelog.date})",
|
23
|
+
"",
|
24
|
+
"| #{headings.join(' | ')} |",
|
25
|
+
"| #{headings.map{|_| ' - |' }.join()}"
|
26
|
+
].join("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Outputs a line or block of text appearing at the top of the change log.
|
30
|
+
#
|
31
|
+
# @param header [String]
|
32
|
+
# @return [String]
|
33
|
+
def write_header(header)
|
34
|
+
"#{header}\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Outputs a line or block as a header for a group.
|
38
|
+
#
|
39
|
+
# @param group [String]
|
40
|
+
# @return [String]
|
41
|
+
def write_group(group)
|
42
|
+
"## #{group}\n\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Outputs a line or block as the body for a change in a group.
|
46
|
+
#
|
47
|
+
# @param ticket [Hash<group: string>]
|
48
|
+
# @return [String]
|
49
|
+
def write_change(ticket)
|
50
|
+
"| "+ @headings.map do |heading|
|
51
|
+
value = ticket.fetch(heading, '-')
|
52
|
+
value = value.join("\n") if value.is_a?(Array)
|
53
|
+
value.gsub("\n", "<br>")
|
54
|
+
end.join(' | ') + " |"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/renogen/generator.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Renogen
|
2
4
|
# This is the conductor of the application
|
3
5
|
class Generator
|
4
6
|
attr_accessor :source, :version, :output_format, :options
|
5
7
|
|
6
|
-
def initialize(version, source, output_format, options={})
|
8
|
+
def initialize(version, source, output_format, options = {})
|
7
9
|
@version = version
|
8
10
|
@source = source
|
9
11
|
@output_format = output_format
|
@@ -16,6 +18,7 @@ module Renogen
|
|
16
18
|
changelog.version = version
|
17
19
|
changelog.date = options['release_date']
|
18
20
|
|
21
|
+
validator.validate!(changelog) if options['allowed_values']&.any?
|
19
22
|
writer.write!(changelog)
|
20
23
|
end
|
21
24
|
|
@@ -32,5 +35,9 @@ module Renogen
|
|
32
35
|
def formatter
|
33
36
|
Renogen::Formatters.obtain(output_format, options)
|
34
37
|
end
|
38
|
+
|
39
|
+
def validator
|
40
|
+
Renogen::ChangeLog::Validator.new(formatter)
|
41
|
+
end
|
35
42
|
end
|
36
43
|
end
|
data/lib/renogen/version.rb
CHANGED
@@ -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
|
@@ -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
|