renogen 1.1.1 → 1.4.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 (47) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +155 -25
  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 +11 -8
  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 +8 -4
  9. data/lib/renogen/cli/param_parser.rb +12 -0
  10. data/lib/renogen/config.rb +16 -15
  11. data/lib/renogen/exceptions.rb +5 -0
  12. data/lib/renogen/exceptions/invalid_item_found.rb +32 -0
  13. data/lib/renogen/exceptions/yaml_file_blank.rb +21 -0
  14. data/lib/renogen/exceptions/yaml_file_invalid.rb +20 -0
  15. data/lib/renogen/extraction_stratagies.rb +0 -2
  16. data/lib/renogen/extraction_stratagies/yaml_file.rb +0 -1
  17. data/lib/renogen/extraction_stratagies/yaml_file/parser.rb +5 -4
  18. data/lib/renogen/extraction_stratagies/yaml_file/reader.rb +20 -11
  19. data/lib/renogen/formatters.rb +2 -0
  20. data/lib/renogen/formatters/base.rb +32 -7
  21. data/lib/renogen/formatters/csv.rb +42 -0
  22. data/lib/renogen/formatters/html.rb +1 -1
  23. data/lib/renogen/formatters/markdown.rb +2 -2
  24. data/lib/renogen/formatters/markdown_table.rb +58 -0
  25. data/lib/renogen/generator.rb +9 -1
  26. data/lib/renogen/version.rb +1 -1
  27. data/lib/renogen/writers/csv.rb +23 -0
  28. data/spec/lib/renogen/change_log/item_spec.rb +1 -1
  29. data/spec/lib/renogen/change_log/model_spec.rb +22 -8
  30. data/spec/lib/renogen/change_log/validator_spec.rb +38 -0
  31. data/spec/lib/renogen/change_log/writer_spec.rb +199 -2
  32. data/spec/lib/renogen/config_spec.rb +7 -2
  33. data/spec/lib/renogen/exceptions/invalid_item_found_spec.rb +35 -0
  34. data/spec/lib/renogen/exceptions/stratagy_not_found_spec.rb +2 -1
  35. data/spec/lib/renogen/{extraction_stratagies/yaml_file/exceptions → exceptions}/yaml_file_blank_spec.rb +1 -1
  36. data/spec/lib/renogen/exceptions/yaml_file_invalid_spec.rb +12 -0
  37. data/spec/lib/renogen/extraction_stratagies/yaml_file/parser_spec.rb +3 -3
  38. data/spec/lib/renogen/extraction_stratagies/yaml_file/reader_spec.rb +11 -5
  39. data/spec/lib/renogen/formatters/base_spec.rb +14 -4
  40. data/spec/lib/renogen/formatters/csv_spec.rb +49 -0
  41. data/spec/lib/renogen/formatters/html_spec.rb +1 -1
  42. data/spec/lib/renogen/formatters/markdown_spec.rb +2 -2
  43. data/spec/spec_helper.rb +5 -0
  44. data/spec/support/renogen_helper.rb +9 -0
  45. metadata +20 -11
  46. data/lib/renogen/extraction_stratagies/yaml_file/exceptions.rb +0 -12
  47. data/lib/renogen/extraction_stratagies/yaml_file/exceptions/yaml_file_blank.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 441ccac5869c9d78abc7c3d163a851c4341d29b2
4
- data.tar.gz: 78e083dde9bba0f04c01c9ce4fe37ac6a3c862b6
2
+ SHA256:
3
+ metadata.gz: 882d9056311e5a9baba8dd05bd1ec8c2ada3e5d84d612abbb15940140e07f9ed
4
+ data.tar.gz: ece836f07e37055b4d84180c7c9522d32814e5c1839e2484e4cf2354acff29f2
5
5
  SHA512:
6
- metadata.gz: c5851785f48aed5505e8b1506c9f5752b6c49c24dca5488110f9a28fdc0d02b33b90c399c3db571beb65d77d908892fdb30f6e8f335bd8b701ec9744f3eb7979
7
- data.tar.gz: 96f6024f0e7decc226d44ce9b55d9f746aa3e2a272a0033b82d219558f1396e65207daae4330f40001b23484bc72a0182cdc48b77b237d92595798e8e9a03d25
6
+ metadata.gz: 0d2edd0513ee545a1b26e0f78846deb543e38ba0227e96d92b6497435916563684f61df58673650e12634e647bdae4e0cde547ee38052d6f53b5f4ea01a2d76e
7
+ data.tar.gz: 6395af9fc76aefa6a3f126cc633aeca9eb80330eb6ab95f59be48f04522ead09f13ab3bf70e96eb923d20c7421d26266634aa7b05f5da52d960ef4ee517477c9
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
10
11
 
11
- ### Installation
12
+ - [Installation](#Installation)
13
+ - [Usage](#Usage)
14
+ - [Configuration](#Configuration)
15
+ - [Frequently Asked Questions](#FAQ)
16
+ - [License](#License)
17
+
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
+ ```
16
38
 
17
- or add the following to your Gemfile
39
+ If you would prefer you can use a prebuild docker image.
18
40
 
19
- `gem 'renogen', :require => false, :group => :development`
41
+ Example:
20
42
 
21
- `$ renogen init # optional Creates directory for notes`
43
+ ```bash
44
+ $ docker run --rm -v `pwd`/.renogen:/.renogen:ro -v `pwd`/change_log:/change_log/ ddazza/renogen <CMD>
45
+ ```
22
46
 
23
- `$ renogen --help # List available options`
47
+ Now, you may initialize your repository with a `change_log` directory and a basic `.renogen` config file:
24
48
 
25
- ### Usage
49
+ ```
50
+ $ renogen init` # optional Creates directory for notes
51
+ ```
52
+
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,34 +93,130 @@ 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:
131
+
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) | |
141
+ | `remove_duplicates` | Remove duplicate items from output release notes. Not applicable when using table formats (e.g`csv` or `markdown_table`). | `false` | |
142
+
143
+ <a name="AllowedValues"></a>
144
+ ## Allowed Values
145
+
146
+ Allowed values enables you to specify a range of allowed values for any default heading. This can be an array, string or
147
+ regular expression:
148
+
149
+ ```yaml
150
+ default_headings:
151
+ - Products
152
+ - Countries
153
+ - User Facing
154
+ Products: !ruby/regexp '/\b(Foo|Bar)\b/'
155
+ Countries: [UK, AUS, FR]
156
+ User Facing: Yes
157
+ ```
158
+
159
+ <a name="FAQ"></a>
160
+ ## Frequently Asked Questions
161
+
162
+ ### Custom formatter
163
+
164
+ You can use your own formatter quite easily.
165
+
166
+ For example, put this in `lib/my_project/renogen_formatter.rb`:
75
167
 
76
- ### Configuration
168
+ ```ruby
169
+ require 'renogen/formatters'
77
170
 
78
- TODO
79
- * How to set configuration with `.renogen` file
80
- * How to change formatted single line
171
+ class MyProject::RenogenFormatter < Renogen::Formatters::Base
172
+ register :xml
173
+
174
+ def write_header(header)
175
+ "<release><header>#{header}</header>"
176
+ end
177
+
178
+ def write_group(group)
179
+ "<group><title>#{group}</title>"
180
+ end
181
+
182
+ def write_group_end
183
+ "</group>"
184
+ end
185
+
186
+ def write_change(change)
187
+ "<change>#{change}</change>"
188
+ end
189
+
190
+ def write_footer(*)
191
+ "</release>"
192
+ end
193
+ end
194
+ ```
195
+
196
+ You have to include that file when running renogen:
197
+
198
+ ```
199
+ $ renogen -I. -Rlib/my_project/renogen_formatter 1.2.3
200
+ ```
201
+
202
+ ### Why does renogen not use renogen
81
203
 
82
- ### Why does renogen not use renogen?
83
204
  The amount of activity and contributes for this project is small and so it is more practical to use a text file.
84
205
 
85
- ### License
206
+ ### How can I run from source
207
+
208
+ ```
209
+ $ git clone git@github.com:DDAZZA/renogen.git
210
+ $ cd ./renogen/
211
+ $ bundle install
212
+ $ bundle exec ./bin/renogen test
213
+ ```
214
+
215
+ ## License
86
216
 
87
217
  Renogen is a programming tool to generate a log of source code changes
88
218
 
89
- Copyright (C) 2015 David Elliott
219
+ Copyright (C) 2015-2020 David Elliott
90
220
 
91
221
  This program is free software; you can redistribute it and/or modify
92
222
  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 + '\']}')
@@ -5,20 +5,14 @@ module Renogen
5
5
  # Object to represent a Changelog/release notes
6
6
  class Model
7
7
  attr_reader :items
8
- attr_accessor :version
8
+ attr_accessor :version, :date
9
9
 
10
10
  def initialize(options={})
11
11
  @version = options[:version]
12
+ @date = options[:date] || Date.today
12
13
  @items = []
13
14
  end
14
15
 
15
- # The title for the change log output
16
- #
17
- # @return [String]
18
- def header
19
- "#{version} (#{Date.today})"
20
- end
21
-
22
16
  # @return [Hash<group_name: change>]
23
17
  def groups
24
18
  items.inject({}) do |hash, change|
@@ -28,6 +22,15 @@ module Renogen
28
22
  end
29
23
  end
30
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
+
31
34
  # Adds a change to the changelog
32
35
  #
33
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(changelog.header)
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
@@ -30,10 +50,22 @@ module Renogen
30
50
  def output_groups(groups)
31
51
  groups.each do |group, changes|
32
52
  puts formatter.write_group(group)
33
- changes.each { |change| output_change(change) }
53
+ deduped_changes(changes).each { |change| output_change(change) }
34
54
  puts formatter.write_group_end
35
55
  end
36
56
  end
57
+
58
+ def deduped_changes(changes)
59
+ return changes unless config.remove_duplicates
60
+
61
+ changes.uniq { |c| c.to_s }
62
+ end
63
+
64
+ private
65
+
66
+ def config
67
+ Config.instance
68
+ end
37
69
  end
38
70
  end
39
71
  end
@@ -20,26 +20,28 @@ module Renogen
20
20
  source = options['source'] || config_instance.input_source
21
21
  options['changelog_path'] ||= config_instance.changelog_path
22
22
  options['old_version'] ||= config_instance.changelog_path
23
+ options['release_date'] ||= Date.today
24
+ options['allowed_values'] ||= config_instance.validations
23
25
 
24
26
  begin
25
27
  generator = Renogen::Generator.new(version, source, format, options)
26
28
  generator.generate!
27
29
  rescue Renogen::Exceptions::Base => e
28
30
  puts e.message
29
- exit -1
31
+ exit 1
30
32
  end
31
33
  end
32
34
 
33
35
  # Initialize the current working directory with an example change
34
36
  def self.init
35
- # TODO Refactor to use Config.instance.changelog_path
37
+ # TODO: Refactor to use Config.instance.changelog_path
36
38
  Dir.mkdir('./change_log')
37
39
  puts "Created './change_log/'"
38
40
 
39
41
  Dir.mkdir('./change_log/next')
40
42
  puts "Created './change_log/next/'"
41
43
 
42
- 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|
43
45
  f.write("Summary:\n")
44
46
  f.write(" identifier: renogen\n")
45
47
  f.write(" link: https://github.com/DDAZZA/renogen\n")
@@ -56,7 +58,7 @@ module Renogen
56
58
 
57
59
  puts "Created './change_log/next/added_renogen_gem.yml'"
58
60
 
59
- File.open(".renogen", 'w') do |f|
61
+ File.open('.renogen', 'w') do |f|
60
62
  f.write("changelog_path: './change_log/'\n")
61
63
  end
62
64
  puts "Created '.renogen'"
@@ -66,6 +68,8 @@ module Renogen
66
68
  #
67
69
  # @param ticket_name [String]
68
70
  def self.new_ticket(ticket_name)
71
+ raise 'You need to provide a ticket_name' if ticket_name.nil?
72
+
69
73
  file_path = File.join(Config.instance.changelog_path, 'next', "#{ticket_name}.yml")
70
74
  File.open(file_path, 'w') do |f|
71
75
  Config.instance.default_headings.each do |h|