renogen 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
-