renogen 1.0.0 → 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 (47) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +162 -23
  3. data/lib/renogen/change_log.rb +1 -0
  4. data/lib/renogen/change_log/item.rb +10 -7
  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 +23 -3
  8. data/lib/renogen/cli.rb +28 -7
  9. data/lib/renogen/cli/param_parser.rb +19 -3
  10. data/lib/renogen/config.rb +15 -14
  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 +41 -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 +8 -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/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 +14 -4
  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
  47. 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: 169e26c4cd97a2fb31a22eada063fca3a25a57cf
4
- data.tar.gz: 5200eff043775217ae1cc7d5e91ec704570346a7
2
+ SHA256:
3
+ metadata.gz: 0d53b818e9ebb6f258fd39cfbe9c83acd9e9818fb49a288c11c86afe38e0f387
4
+ data.tar.gz: 1960bf0af875ef179e1f34826caf9ef56e7dec676c5bd7db44f9c05151448e53
5
5
  SHA512:
6
- metadata.gz: 3b52c38810a2b055fa83fe9ece7203b3ba9fd9360c0fefd49ca4e7fdd89d7691b899a7bb652367368ff6086974dc0e4b2038405923878a736c9e5b448519c87e
7
- data.tar.gz: a5e624d7fffa82c23fd4413ae76a1053133034e2c0b837664b71f2c5e3d0ce0972865ada62346885be4c23183050c12fd923d0f5d1228ed3c7a482c56d79037d
6
+ metadata.gz: 579845fd96294be9ef4a70ac58f7c9b6097951b8343013a7fa98f1ffc7ef42758ffa8ce7bd7b3adfb5eea23530f237032c792e887d0296f7a72e98fac2dc1203
7
+ data.tar.gz: aaa2da2cdaaa0c7ac48e3d7f8dcfbbdc82230d643c6d660a4d8453c5d8aa5eb03e84546afd7e1f154440dadabf588b14e9c9d17f1fff651f1a41cf2a047c78bf
data/README.md CHANGED
@@ -2,35 +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
- ### Installation
5
+ This renogen can not do and will have to be reviewed manually
6
+
7
+ - Order the notes in the orrect order (e.g. if a task has to be run before/after something else)
8
+ - Remove Duplicate notes that might be added (e.g. 2 tickets might want to run the same task)
9
+
10
+ ## Contents
11
+
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
6
20
 
7
21
  To install Renogen, use the following command:
8
22
 
9
- `$ 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.
40
+
41
+ Example:
10
42
 
11
- or add the following to your Gemfile
43
+ ```bash
44
+ $ docker run --rm -v `pwd`/.renogen:/.renogen:ro -v `pwd`/change_log:/change_log/ ddazza/renogen <CMD>
45
+ ```
12
46
 
13
- `gem 'renogen', :require => false, :group => :development`
47
+ Now, you may initialize your repository with a `change_log` directory and a basic `.renogen` config file:
14
48
 
15
- `$ renogen init # optional Creates directory for notes`
16
- `$ renogen --help # List available options
49
+ ```
50
+ $ renogen init` # optional Creates directory for notes
51
+ ```
17
52
 
18
- ### Usage
53
+ <a name="Usage"></a>
54
+ ## Usage
19
55
 
20
56
  To generate your notes run the following command
21
57
 
22
- `$ renogen <VERSION> # e.g v1.2.1`
58
+ ```
59
+ $ renogen <VERSION> # e.g v1.2.1
60
+ ```
23
61
 
24
62
  Unfortunatly renogen cant write documentation for your change.
25
63
  By default renogen uses the yaml file stratagy to extract your notes
26
64
 
27
- `$ renogen --help # list available command options`
65
+ ```
66
+ $ renogen --help # list available command options
67
+ ```
68
+
69
+ ### Adding YAML feature notes
28
70
 
29
- #### Adding YAML feature notes
71
+ You can create a new file within the 'next' version folder (default: `change_log/next/`) manually:
30
72
 
31
- Create a new file within the 'next' version folder(default:'change_log/next/')
73
+ Example feature note:
32
74
 
33
- Example feature note
34
75
  ```yaml
35
76
  # change_log/next/example.yml
36
77
  my_formatted_single_line:
@@ -52,31 +93,129 @@ my_list:
52
93
  - e.g. run this as well
53
94
  ```
54
95
 
55
- #### Usage Examples
96
+ You can also use the `new` command to create a feature note YAML file in the 'next' version folder:
56
97
 
57
- 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
+ ```
101
+
102
+ ### Usage Examples
103
+
104
+ Prepend your notes to a changelog file (TODO make command simple)
58
105
 
59
- `$ renogen --format markdown v1.2.1 > CHANGELOG.md | cat - CHANGELOG > CHANGELOG.tmp && mv CHANGELOG.tmp CHANGELOG`
106
+ ```
107
+ $ renogen --format markdown v1.2.1 > CHANGELOG.md | cat - CHANGELOG > CHANGELOG.tmp && mv CHANGELOG.tmp CHANGELOG
108
+ ```
60
109
 
61
110
  Writes notes to html file
62
111
 
63
- `$ 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`
64
119
 
65
120
  Print all notes since v1.0.0 as text
66
121
 
67
- `$ 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
+
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
160
+
161
+ ### Custom formatter
162
+
163
+ You can use your own formatter quite easily.
164
+
165
+ For example, put this in `lib/my_project/renogen_formatter.rb`:
68
166
 
69
- ### Configuration
167
+ ```ruby
168
+ require 'renogen/formatters'
70
169
 
71
- TODO
72
- * How to set configuration with `.renogen` file
73
- * How to change formatted single line
170
+ class MyProject::RenogenFormatter < Renogen::Formatters::Base
171
+ register :xml
172
+
173
+ def write_header(header)
174
+ "<release><header>#{header}</header>"
175
+ end
176
+
177
+ def write_group(group)
178
+ "<group><title>#{group}</title>"
179
+ end
180
+
181
+ def write_group_end
182
+ "</group>"
183
+ end
184
+
185
+ def write_change(change)
186
+ "<change>#{change}</change>"
187
+ end
188
+
189
+ def write_footer(*)
190
+ "</release>"
191
+ end
192
+ end
193
+ ```
194
+
195
+ You have to include that file when running renogen:
196
+
197
+ ```
198
+ $ renogen -I. -Rlib/my_project/renogen_formatter 1.2.3
199
+ ```
200
+
201
+ ### Why does renogen not use renogen
202
+
203
+ The amount of activity and contributes for this project is small and so it is more practical to use a text file.
204
+
205
+ ### How can I run from source
206
+
207
+ ```
208
+ $ git clone git@github.com:DDAZZA/renogen.git
209
+ $ cd ./renogen/
210
+ $ bundle install
211
+ $ bundle exec ./bin/renogen test
212
+ ```
74
213
 
75
- ### License
214
+ ## License
76
215
 
77
216
  Renogen is a programming tool to generate a log of source code changes
78
217
 
79
- Copyright (C) 2015 David Elliott
218
+ Copyright (C) 2015-2020 David Elliott
80
219
 
81
220
  This program is free software; you can redistribute it and/or modify
82
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
@@ -14,12 +15,14 @@ module Renogen
14
15
  #
15
16
  # @return [String]
16
17
  def to_s
18
+ return '' unless change
19
+
17
20
  case change.class.to_s
18
- when String.to_s
21
+ when 'String'
19
22
  format_multiline(change)
20
- when Hash.to_s
23
+ when 'Hash'
21
24
  format_oneline(change)
22
- when Array.to_s
25
+ when 'Array'
23
26
  format_array(change)
24
27
  else
25
28
  raise TypeError
@@ -45,12 +48,12 @@ module Renogen
45
48
  end
46
49
 
47
50
  def format_array(change)
48
- # TODO should return a string
51
+ # TODO: should return a string
49
52
  change
50
53
  end
51
54
 
52
55
  def format_oneline(change)
53
- # TODO Refactor
56
+ # TODO: Refactor
54
57
  string = config.single_line_format.downcase.gsub('\n', '\n ')
55
58
  config.supported_keys.each do |key|
56
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
@@ -23,7 +43,7 @@ module Renogen
23
43
  if change.list?
24
44
  change.each { |item| puts formatter.write_change(item) }
25
45
  else
26
- puts formatter.write_change(change.to_s)
46
+ puts formatter.write_change(change.to_s) if change.to_s.size > 0
27
47
  end
28
48
  end
29
49
 
@@ -10,32 +10,38 @@ module Renogen
10
10
  # @param args [Array]
11
11
  def self.run(args)
12
12
  return init if args.first == 'init'
13
+ return new_ticket(args[1]) if args.first == 'new'
14
+
13
15
  param_parser = ParamParser.new(args)
14
16
  version, options = param_parser.parse
17
+ config_instance = Config.instance
15
18
 
16
- format = options['format'] || Config.instance.output_format
17
- source = options['source'] || Config.instance.input_source
18
- options['changelog_path'] ||= Config.instance.changelog_path
19
- options['old_version'] ||= Config.instance.changelog_path
19
+ format = options['format'] || config_instance.output_format
20
+ source = options['source'] || config_instance.input_source
21
+ options['changelog_path'] ||= config_instance.changelog_path
22
+ options['old_version'] ||= config_instance.changelog_path
23
+ options['release_date'] ||= Date.today
24
+ options['allowed_values'] ||= config_instance.validations
20
25
 
21
26
  begin
22
27
  generator = Renogen::Generator.new(version, source, format, options)
23
28
  generator.generate!
24
29
  rescue Renogen::Exceptions::Base => e
25
30
  puts e.message
26
- exit -1
31
+ exit 1
27
32
  end
28
33
  end
29
34
 
30
35
  # Initialize the current working directory with an example change
31
36
  def self.init
37
+ # TODO: Refactor to use Config.instance.changelog_path
32
38
  Dir.mkdir('./change_log')
33
39
  puts "Created './change_log/'"
34
40
 
35
41
  Dir.mkdir('./change_log/next')
36
42
  puts "Created './change_log/next/'"
37
43
 
38
- 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|
39
45
  f.write("Summary:\n")
40
46
  f.write(" identifier: renogen\n")
41
47
  f.write(" link: https://github.com/DDAZZA/renogen\n")
@@ -52,10 +58,25 @@ module Renogen
52
58
 
53
59
  puts "Created './change_log/next/added_renogen_gem.yml'"
54
60
 
55
- File.open(".renogen", 'w') do |f|
61
+ File.open('.renogen', 'w') do |f|
56
62
  f.write("changelog_path: './change_log/'\n")
57
63
  end
58
64
  puts "Created '.renogen'"
59
65
  end
66
+
67
+ # Creates a new template file
68
+ #
69
+ # @param ticket_name [String]
70
+ def self.new_ticket(ticket_name)
71
+ raise 'You need to provide a ticket_name' if ticket_name.nil?
72
+
73
+ file_path = File.join(Config.instance.changelog_path, 'next', "#{ticket_name}.yml")
74
+ File.open(file_path, 'w') do |f|
75
+ Config.instance.default_headings.each do |h|
76
+ f.write("#{h}:\n")
77
+ end
78
+ end
79
+ puts "Created '#{file_path}'"
80
+ end
60
81
  end
61
82
  end