renogen 1.2.0 → 1.4.1

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 (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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9c597a603a1ff6629766e2fca60f6970a75bb1e3
4
- data.tar.gz: 70ff70d1bcd0fe5fba73dcb6a7a04b3a70652630
2
+ SHA256:
3
+ metadata.gz: f41746c67c1a940656716163553293ab5ddcdc6c3d763e577ac0117df9ec0d8c
4
+ data.tar.gz: 0bffdb719fb31fac03fc669a4acf5d17692390b9dd94122f4361faac1de4fc45
5
5
  SHA512:
6
- metadata.gz: 22e630d7505723cf02a2c6c66853c74ae1f98633e0d102cde31061b7dcc8ab1d6bdca9cb22c438f6cb746a8b1ecc5cf295b4fabfa9dff1c49b43e0b7421014ea
7
- data.tar.gz: c94d1ae2b66072bbfcdf8d4960fa3f29caf58a0aaabb76a32d4f164e6eae73bff06a0f6040f64aaaab99b685cc82a92909d11f8a40841e1ec642768f60539c72
6
+ metadata.gz: c3d6be1ff1031affac80ea17f0701e5db0ffe7515e622b6101ce451bd1714450484423616dc160e6c20a8692928956b5edb47c662b6c5288f1e527d0a894cf05
7
+ data.tar.gz: f81ad8c1d96c818b9786c6d3fb4dae87d810e7db9a35c073b34b934157e08e6c84bf0e4625241dbf8e62adae477919ef5744483b70d118d23821615fc38ddd58
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
+ ```
16
26
 
17
- or add the following to your Gemfile
27
+ or add the following to your Gemfile when using Bundler
18
28
 
19
- `gem 'renogen', :require => false, :group => :development`
29
+ ```
30
+ gem 'renogen', require: false, group: :development
31
+ ```
20
32
 
21
- `$ renogen init # optional Creates directory for notes`
33
+ and run
22
34
 
23
- `$ renogen --help # List available options`
35
+ ```
36
+ bundle install
37
+ ```
38
+
39
+ If you would prefer you can use a prebuild docker image.
40
+
41
+ Example:
42
+
43
+ ```bash
44
+ $ docker run --rm -v `pwd`/.renogen:/.renogen:ro -v `pwd`/change_log:/change_log/ ddazza/renogen <CMD>
45
+ ```
24
46
 
25
- ### Usage
47
+ Now, you may initialize your repository with a `change_log` directory and a basic `.renogen` config file:
48
+
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,31 +93,78 @@ 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:
97
+
98
+ ```
99
+ $ renogen new TICKET_NAME # creates ./change_log/next/TICKET_NAME.yml`
100
+ ```
63
101
 
64
- Prepend your notes to a changelog file(TODO make command simple)
102
+ ### Usage Examples
65
103
 
66
- `$ renogen --format markdown v1.2.1 > CHANGELOG.md | cat - CHANGELOG > CHANGELOG.tmp && mv CHANGELOG.tmp CHANGELOG`
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` | |
75
142
 
76
- ### Configuration
143
+ <a name="AllowedValues"></a>
144
+ ## Allowed Values
77
145
 
78
- TODO
79
- * How to set configuration with `.renogen` file
80
- * How to change formatted single line
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
81
161
 
82
162
  ### Custom formatter
83
163
 
84
164
  You can use your own formatter quite easily.
85
165
 
86
166
  For example, put this in `lib/my_project/renogen_formatter.rb`:
167
+
87
168
  ```ruby
88
169
  require 'renogen/formatters'
89
170
 
@@ -114,16 +195,28 @@ end
114
195
 
115
196
  You have to include that file when running renogen:
116
197
 
117
- `$ renogen -I. -Rlib/my_project/renogen_formatter 1.2.3`
198
+ ```
199
+ $ renogen -I. -Rlib/my_project/renogen_formatter 1.2.3
200
+ ```
201
+
202
+ ### Why does renogen not use renogen
118
203
 
119
- ### Why does renogen not use renogen?
120
204
  The amount of activity and contributes for this project is small and so it is more practical to use a text file.
121
205
 
122
- ### 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
123
216
 
124
217
  Renogen is a programming tool to generate a log of source code changes
125
218
 
126
- Copyright (C) 2015 David Elliott
219
+ Copyright (C) 2015-2020 David Elliott
127
220
 
128
221
  This program is free software; you can redistribute it and/or modify
129
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 + '\']}')
@@ -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
@@ -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
data/lib/renogen/cli.rb CHANGED
@@ -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'"
@@ -67,6 +68,8 @@ module Renogen
67
68
  #
68
69
  # @param ticket_name [String]
69
70
  def self.new_ticket(ticket_name)
71
+ raise 'You need to provide a ticket_name' if ticket_name.nil?
72
+
70
73
  file_path = File.join(Config.instance.changelog_path, 'next', "#{ticket_name}.yml")
71
74
  File.open(file_path, 'w') do |f|
72
75
  Config.instance.default_headings.each do |h|