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.
Files changed (42) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +112 -27
  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 +22 -2
  8. data/lib/renogen/cli.rb +6 -4
  9. data/lib/renogen/config.rb +15 -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 +41 -0
  21. data/lib/renogen/formatters/markdown_table.rb +58 -0
  22. data/lib/renogen/generator.rb +8 -1
  23. data/lib/renogen/version.rb +1 -1
  24. data/lib/renogen/writers/csv.rb +23 -0
  25. data/spec/lib/renogen/change_log/item_spec.rb +1 -1
  26. data/spec/lib/renogen/change_log/model_spec.rb +1 -1
  27. data/spec/lib/renogen/change_log/validator_spec.rb +38 -0
  28. data/spec/lib/renogen/config_spec.rb +7 -2
  29. data/spec/lib/renogen/exceptions/invalid_item_found_spec.rb +35 -0
  30. data/spec/lib/renogen/exceptions/stratagy_not_found_spec.rb +2 -1
  31. data/spec/lib/renogen/{extraction_stratagies/yaml_file/exceptions → exceptions}/yaml_file_blank_spec.rb +1 -1
  32. data/spec/lib/renogen/exceptions/yaml_file_invalid_spec.rb +12 -0
  33. data/spec/lib/renogen/extraction_stratagies/yaml_file/parser_spec.rb +3 -3
  34. data/spec/lib/renogen/extraction_stratagies/yaml_file/reader_spec.rb +11 -5
  35. data/spec/lib/renogen/formatters/base_spec.rb +8 -8
  36. data/spec/lib/renogen/formatters/csv_spec.rb +49 -0
  37. data/spec/spec_helper.rb +5 -0
  38. data/spec/support/renogen_helper.rb +9 -0
  39. metadata +15 -6
  40. data/lib/renogen/extraction_stratagies/yaml_file/exceptions.rb +0 -12
  41. data/lib/renogen/extraction_stratagies/yaml_file/exceptions/yaml_file_blank.rb +0 -25
  42. data/spec/lib/renogen/change_log/writer_spec.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 678094f7d0bc73ec7bcbce26bc6b247d77227383
4
- data.tar.gz: 897ed1b230c1bbfcdc625e678528543042ba3210
2
+ SHA256:
3
+ metadata.gz: 0d53b818e9ebb6f258fd39cfbe9c83acd9e9818fb49a288c11c86afe38e0f387
4
+ data.tar.gz: 1960bf0af875ef179e1f34826caf9ef56e7dec676c5bd7db44f9c05151448e53
5
5
  SHA512:
6
- metadata.gz: 5bb3adc8c88af3a84f8784d6237df86ebc1d479f0131c7ec967bcd0cef2b94731f01ef369614ee950df9eb398aa44ba6f9ae17b106044f85af2be69eb48b992b
7
- data.tar.gz: 8dba5a1b2198b4aa7b515c816c3c8638c3f3efa0192b1ab5ac834b5d80acdb8a9b5f3c3e4f1b2d7663ca1293d786cbce6b177474a3cd2e6ebade0d065cf53354
6
+ metadata.gz: 579845fd96294be9ef4a70ac58f7c9b6097951b8343013a7fa98f1ffc7ef42758ffa8ce7bd7b3adfb5eea23530f237032c792e887d0296f7a72e98fac2dc1203
7
+ data.tar.gz: aaa2da2cdaaa0c7ac48e3d7f8dcfbbdc82230d643c6d660a4d8453c5d8aa5eb03e84546afd7e1f154440dadabf588b14e9c9d17f1fff651f1a41cf2a047c78bf
data/README.md CHANGED
@@ -2,42 +2,76 @@
2
2
 
3
3
  Renogen or Re(lease) No(tes) Gen(erator) is a development tool to separate feature notes from product versions.
4
4
 
5
-
6
5
  This renogen can not do and will have to be reviewed manually
6
+
7
7
  - Order the notes in the orrect order (e.g. if a task has to be run before/after something else)
8
8
  - Remove Duplicate notes that might be added (e.g. 2 tickets might want to run the same task)
9
9
 
10
+ ## Contents
11
+
12
+ - [Installation](#Installation)
13
+ - [Usage](#Usage)
14
+ - [Configuration](#Configuration)
15
+ - [Frequently Asked Questions](#FAQ)
16
+ - [License](#License)
10
17
 
11
- ### Installation
18
+ <a name="Installation"></a>
19
+ ## Installation
12
20
 
13
21
  To install Renogen, use the following command:
14
22
 
15
- `$ gem install renogen`
23
+ ```
24
+ $ gem install renogen
25
+ ```
26
+
27
+ or add the following to your Gemfile when using Bundler
28
+
29
+ ```
30
+ gem 'renogen', require: false, group: :development
31
+ ```
32
+
33
+ and run
34
+
35
+ ```
36
+ bundle install
37
+ ```
38
+
39
+ If you would prefer you can use a prebuild docker image.
16
40
 
17
- or add the following to your Gemfile
41
+ Example:
18
42
 
19
- `gem 'renogen', :require => false, :group => :development`
43
+ ```bash
44
+ $ docker run --rm -v `pwd`/.renogen:/.renogen:ro -v `pwd`/change_log:/change_log/ ddazza/renogen <CMD>
45
+ ```
20
46
 
21
- `$ renogen init # optional Creates directory for notes`
47
+ Now, you may initialize your repository with a `change_log` directory and a basic `.renogen` config file:
22
48
 
23
- `$ renogen --help # List available options`
49
+ ```
50
+ $ renogen init` # optional Creates directory for notes
51
+ ```
24
52
 
25
- ### Usage
53
+ <a name="Usage"></a>
54
+ ## Usage
26
55
 
27
56
  To generate your notes run the following command
28
57
 
29
- `$ renogen <VERSION> # e.g v1.2.1`
58
+ ```
59
+ $ renogen <VERSION> # e.g v1.2.1
60
+ ```
30
61
 
31
62
  Unfortunatly renogen cant write documentation for your change.
32
63
  By default renogen uses the yaml file stratagy to extract your notes
33
64
 
34
- `$ renogen --help # list available command options`
65
+ ```
66
+ $ renogen --help # list available command options
67
+ ```
68
+
69
+ ### Adding YAML feature notes
35
70
 
36
- #### Adding YAML feature notes
71
+ You can create a new file within the 'next' version folder (default: `change_log/next/`) manually:
37
72
 
38
- Create a new file within the 'next' version folder(default:'change_log/next/')
73
+ Example feature note:
39
74
 
40
- Example feature note
41
75
  ```yaml
42
76
  # change_log/next/example.yml
43
77
  my_formatted_single_line:
@@ -59,31 +93,77 @@ my_list:
59
93
  - e.g. run this as well
60
94
  ```
61
95
 
62
- #### Usage Examples
96
+ You can also use the `new` command to create a feature note YAML file in the 'next' version folder:
63
97
 
64
- Prepend your notes to a changelog file(TODO make command simple)
98
+ ```
99
+ $ renogen new TICKET_NAME # creates ./change_log/next/TICKET_NAME.yml`
100
+ ```
65
101
 
66
- `$ renogen --format markdown v1.2.1 > CHANGELOG.md | cat - CHANGELOG > CHANGELOG.tmp && mv CHANGELOG.tmp CHANGELOG`
102
+ ### Usage Examples
103
+
104
+ Prepend your notes to a changelog file (TODO make command simple)
105
+
106
+ ```
107
+ $ renogen --format markdown v1.2.1 > CHANGELOG.md | cat - CHANGELOG > CHANGELOG.tmp && mv CHANGELOG.tmp CHANGELOG
108
+ ```
67
109
 
68
110
  Writes notes to html file
69
111
 
70
- `$ renogen --format html v1.2.1 > v1_2_1.html`
112
+ ```
113
+ $ renogen --format html v1.2.1 > v1_2_1.html
114
+ ```
115
+
116
+ Writes note to csv file
117
+
118
+ `$ renogen --format csv v1.2.1 > v1_2_1.csv`
71
119
 
72
120
  Print all notes since v1.0.0 as text
73
121
 
74
- `$ renogen --format text -l v1.0.0 v1.2.1`
122
+ ```
123
+ $ renogen --format text -l v1.0.0 v1.2.1
124
+ ```
125
+
126
+ <a name="Configuration"></a>
127
+ ## Configuration
128
+
129
+ Renogen tries to read the file `.renogen` in the working directory to load its configuration. The file is in YAML format
130
+ with the following keys:
75
131
 
76
- ### Configuration
132
+ | key | meaning | default value | configuration example |
133
+ |----------------------|----------|---------------|-----------------------|
134
+ | `single_line_format` | A template for generating a single line of text from a YAML dictionary in a feature note file. Each dictionary key in the template gets replaced by the value for that key. | `summary (see link)` | `[#ticket](https://github.com/renogen/issue/ticket): summary` |
135
+ | `supported_keys` | YAML dictionary keys allowed in dictionary feature notes. Ignored for dictionaries where rules apply. | `%w[identifier summary link]` | |
136
+ | `input_source` | The format of the feature note files. Currently, only `yaml` is supported. | `yaml` | |
137
+ | `output_format` | The default output format when generating release notes. | `markdown` | `html` |
138
+ | `changelog_path` | The directory where the feature note files are stored. | `./change_log` | `./doc/src/changes` |
139
+ | `default_headings` | The headings/group names that will be printed into a feature note file created by the `new` command. Ignored when there is a rule defined for the given file name. | `%w[Summary Detailed Tasks]` | `%w[Title Description Deployment]` |
140
+ | `allowed_values` | Allowed values for default headings. See [Allowed Values](#AllowedValues). | `{}` (none) | |
77
141
 
78
- TODO
79
- * How to set configuration with `.renogen` file
80
- * How to change formatted single line
142
+ <a name="AllowedValues"></a>
143
+ ## Allowed Values
144
+
145
+ Allowed values enables you to specify a range of allowed values for any default heading. This can be an array, string or
146
+ regular expression:
147
+
148
+ ```yaml
149
+ default_headings:
150
+ - Products
151
+ - Countries
152
+ - User Facing
153
+ Products: !ruby/regexp '/\b(Foo|Bar)\b/'
154
+ Countries: [UK, AUS, FR]
155
+ User Facing: Yes
156
+ ```
157
+
158
+ <a name="FAQ"></a>
159
+ ## Frequently Asked Questions
81
160
 
82
161
  ### Custom formatter
83
162
 
84
163
  You can use your own formatter quite easily.
85
164
 
86
165
  For example, put this in `lib/my_project/renogen_formatter.rb`:
166
+
87
167
  ```ruby
88
168
  require 'renogen/formatters'
89
169
 
@@ -114,23 +194,28 @@ end
114
194
 
115
195
  You have to include that file when running renogen:
116
196
 
117
- `$ renogen -I. -Rlib/my_project/renogen_formatter 1.2.3`
197
+ ```
198
+ $ renogen -I. -Rlib/my_project/renogen_formatter 1.2.3
199
+ ```
200
+
201
+ ### Why does renogen not use renogen
118
202
 
119
- ### Why does renogen not use renogen?
120
203
  The amount of activity and contributes for this project is small and so it is more practical to use a text file.
121
204
 
122
- ### How can I run from source?
205
+ ### How can I run from source
206
+
123
207
  ```
124
208
  $ git clone git@github.com:DDAZZA/renogen.git
125
209
  $ cd ./renogen/
126
210
  $ bundle install
127
211
  $ bundle exec ./bin/renogen test
128
212
  ```
129
- ### License
213
+
214
+ ## License
130
215
 
131
216
  Renogen is a programming tool to generate a log of source code changes
132
217
 
133
- Copyright (C) 2015 David Elliott
218
+ Copyright (C) 2015-2020 David Elliott
134
219
 
135
220
  This program is free software; you can redistribute it and/or modify
136
221
  it under the terms of the GNU General Public License as published by
@@ -5,5 +5,6 @@ module Renogen
5
5
  require_relative 'change_log/group'
6
6
  require_relative 'change_log/writer'
7
7
  require_relative 'change_log/model'
8
+ require_relative 'change_log/validator'
8
9
  end
9
10
  end
@@ -3,9 +3,10 @@ module Renogen
3
3
  # Object to represent single change item
4
4
  class Item
5
5
  attr_accessor :change
6
- attr_reader :group_name
6
+ attr_reader :group_name, :ticket_id
7
7
 
8
- def initialize(group_name, change, options={})
8
+ def initialize(ticket_id, group_name, change, options={})
9
+ @ticket_id = ticket_id
9
10
  @group_name = group_name
10
11
  @change = change
11
12
  end
@@ -15,6 +16,7 @@ module Renogen
15
16
  # @return [String]
16
17
  def to_s
17
18
  return '' unless change
19
+
18
20
  case change.class.to_s
19
21
  when 'String'
20
22
  format_multiline(change)
@@ -46,12 +48,12 @@ module Renogen
46
48
  end
47
49
 
48
50
  def format_array(change)
49
- # TODO should return a string
51
+ # TODO: should return a string
50
52
  change
51
53
  end
52
54
 
53
55
  def format_oneline(change)
54
- # TODO Refactor
56
+ # TODO: Refactor
55
57
  string = config.single_line_format.downcase.gsub('\n', '\n ')
56
58
  config.supported_keys.each do |key|
57
59
  string = string.gsub(key, '#{change[\'' + key + '\']}')
@@ -22,6 +22,15 @@ module Renogen
22
22
  end
23
23
  end
24
24
 
25
+ # @return [Hash<ticket id: string>]
26
+ def tickets
27
+ items.inject({}) do |hash, change|
28
+ hash[change.ticket_id] ||= {}
29
+ hash[change.ticket_id][change.group_name] = change.to_s
30
+ hash
31
+ end
32
+ end
33
+
25
34
  # Adds a change to the changelog
26
35
  #
27
36
  # @param change [Renogen::ChangeLog::Item]
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Renogen
4
+ module ChangeLog
5
+ # Validates the change log
6
+ class Validator
7
+ def initialize(formatter)
8
+ @formatter = formatter
9
+ @validations = formatter.options['allowed_values']
10
+ end
11
+
12
+ # Validates the change log
13
+ #
14
+ # @param changelog [ChangeLog::Model]
15
+ def validate!(changelog)
16
+ validate_headings(changelog)
17
+ end
18
+
19
+ protected
20
+
21
+ attr_reader :formatter, :validations
22
+
23
+ def validate_headings(changelog)
24
+ return if validations.nil?
25
+ return if changelog.items.none? { |item| validations.key?(item.group_name) }
26
+
27
+ validate_properties(changelog)
28
+ end
29
+
30
+ private
31
+
32
+ def validate_properties(changelog)
33
+ invalid_items = []
34
+ validations.each do |heading, values|
35
+ items_to_select = changelog.items.select { |log| log.group_name == heading }
36
+ invalid_values = items_to_select.map do |i|
37
+ changes = changes_to_validate(i.change)
38
+ next changes - values if values.is_a?(Array)
39
+ next unless values.is_a?(Regexp)
40
+
41
+ changes.detect { |c| c !~ values } # return anything that does not match the regexp.
42
+ end
43
+
44
+ invalid_values = invalid_values.flatten.compact.uniq # remove duplicates and nils
45
+ next if invalid_values.empty?
46
+
47
+ invalid_items << { invalid_value: invalid_values, valid_values: values, group_name: heading }
48
+ end
49
+
50
+ invalid_items = invalid_items.flatten
51
+ raise(Renogen::Exceptions::InvalidItemFound, invalid_items) unless invalid_items.empty?
52
+ end
53
+
54
+ def changes_to_validate(change)
55
+ return [change] if change.is_a? String
56
+
57
+ change
58
+ end
59
+ end
60
+ end
61
+ end
@@ -10,9 +10,29 @@ module Renogen
10
10
  #
11
11
  # @param changelog [ChangeLog::Model]
12
12
  def write!(changelog)
13
- puts formatter.write_header(formatter.header(changelog))
13
+ puts formatter.write_header(formatter.header(changelog)) unless formatter.write_header(formatter.header(changelog)).nil?
14
+ if formatter.table_formatter?
15
+ write_by_table!(changelog)
16
+ else
17
+ write_by_group!(changelog)
18
+ end
19
+ puts formatter.write_footer(changelog) unless formatter.write_footer(changelog).nil?
20
+ end
21
+
22
+ # Writes out the change log by group
23
+ #
24
+ # @param changelog [ChangeLog::Model]
25
+ def write_by_group!(changelog)
14
26
  output_groups(changelog.groups)
15
- puts formatter.write_footer(changelog)
27
+ end
28
+
29
+ # Writes out the change log by item
30
+ #
31
+ # @param changelog [ChangeLog::Model]
32
+ def write_by_table!(changelog)
33
+ changelog.tickets.each do |_, ticket|
34
+ puts formatter.write_change(ticket)
35
+ end
16
36
  end
17
37
 
18
38
  protected
@@ -21,26 +21,27 @@ module Renogen
21
21
  options['changelog_path'] ||= config_instance.changelog_path
22
22
  options['old_version'] ||= config_instance.changelog_path
23
23
  options['release_date'] ||= Date.today
24
+ options['allowed_values'] ||= config_instance.validations
24
25
 
25
26
  begin
26
27
  generator = Renogen::Generator.new(version, source, format, options)
27
28
  generator.generate!
28
29
  rescue Renogen::Exceptions::Base => e
29
30
  puts e.message
30
- exit -1
31
+ exit 1
31
32
  end
32
33
  end
33
34
 
34
35
  # Initialize the current working directory with an example change
35
36
  def self.init
36
- # TODO Refactor to use Config.instance.changelog_path
37
+ # TODO: Refactor to use Config.instance.changelog_path
37
38
  Dir.mkdir('./change_log')
38
39
  puts "Created './change_log/'"
39
40
 
40
41
  Dir.mkdir('./change_log/next')
41
42
  puts "Created './change_log/next/'"
42
43
 
43
- File.open("./change_log/next/added_renogen_gem.yml", 'w') do |f|
44
+ File.open('./change_log/next/added_renogen_gem.yml', 'w') do |f|
44
45
  f.write("Summary:\n")
45
46
  f.write(" identifier: renogen\n")
46
47
  f.write(" link: https://github.com/DDAZZA/renogen\n")
@@ -57,7 +58,7 @@ module Renogen
57
58
 
58
59
  puts "Created './change_log/next/added_renogen_gem.yml'"
59
60
 
60
- File.open(".renogen", 'w') do |f|
61
+ File.open('.renogen', 'w') do |f|
61
62
  f.write("changelog_path: './change_log/'\n")
62
63
  end
63
64
  puts "Created '.renogen'"
@@ -68,6 +69,7 @@ module Renogen
68
69
  # @param ticket_name [String]
69
70
  def self.new_ticket(ticket_name)
70
71
  raise 'You need to provide a ticket_name' if ticket_name.nil?
72
+
71
73
  file_path = File.join(Config.instance.changelog_path, 'next', "#{ticket_name}.yml")
72
74
  File.open(file_path, 'w') do |f|
73
75
  Config.instance.default_headings.each do |h|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'singleton'
2
4
  require 'yaml'
3
5
 
@@ -5,19 +7,20 @@ module Renogen
5
7
  # Stores configuratin values to be used by the libary
6
8
  class Config
7
9
  include Singleton
8
- attr_accessor :single_line_format, :input_source, :output_format, :supported_keys, :changelog_path, :default_headings
10
+ attr_accessor :single_line_format, :input_source, :output_format, :supported_keys, :changelog_path,
11
+ :default_headings, :validations
9
12
 
10
13
  def initialize
11
14
  config_file = load_yaml_config
12
- self.single_line_format = config_file['single_line_format'] || 'summary (see link)'.freeze
13
- self.supported_keys = config_file['supported_keys'] || ['identifier', 'link', 'summary'].freeze
14
- self.input_source = config_file['input_source'] || 'yaml'.freeze
15
- self.output_format = config_file['output_format'] || 'markdown'.freeze
16
- self.changelog_path = config_file['changelog_path'] || './change_log'.freeze
17
- self.default_headings = config_file['default_headings'] || %w(Summary Detailed Tasks).freeze
15
+ self.single_line_format = config_file['single_line_format'] || 'summary (see link)'
16
+ self.supported_keys = config_file['supported_keys'] || %w(identifier link summary)
17
+ self.input_source = config_file['input_source'] || 'yaml'
18
+ self.output_format = config_file['output_format'] || 'markdown'
19
+ self.changelog_path = config_file['changelog_path'] || './change_log'
20
+ self.default_headings = config_file['default_headings'] || %w(Summary Detailed Tasks)
21
+ self.validations = config_file['allowed_values']
18
22
  end
19
23
 
20
-
21
24
  # Renogen configuration extension
22
25
  # a block can be provided to programatily setup configuration values
23
26
  def self.configure
@@ -26,13 +29,10 @@ module Renogen
26
29
 
27
30
  private
28
31
 
29
- def load_yaml_config(config_file_path='.renogen')
30
- begin
31
- YAML.load_file(config_file_path)
32
- rescue
33
- {}
34
- end
32
+ def load_yaml_config(config_file_path = '.renogen')
33
+ YAML.load_file(config_file_path)
34
+ rescue StandardError
35
+ {}
35
36
  end
36
37
  end
37
38
  end
38
-