renogen 1.0.1 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +162 -23
- data/lib/renogen/change_log.rb +1 -0
- data/lib/renogen/change_log/item.rb +6 -4
- data/lib/renogen/change_log/model.rb +11 -8
- data/lib/renogen/change_log/validator.rb +61 -0
- data/lib/renogen/change_log/writer.rb +22 -2
- data/lib/renogen/cli.rb +28 -7
- data/lib/renogen/cli/param_parser.rb +19 -3
- data/lib/renogen/config.rb +15 -14
- data/lib/renogen/exceptions.rb +5 -0
- data/lib/renogen/exceptions/invalid_item_found.rb +32 -0
- data/lib/renogen/exceptions/yaml_file_blank.rb +21 -0
- data/lib/renogen/exceptions/yaml_file_invalid.rb +20 -0
- data/lib/renogen/extraction_stratagies.rb +0 -2
- data/lib/renogen/extraction_stratagies/yaml_file.rb +0 -1
- data/lib/renogen/extraction_stratagies/yaml_file/parser.rb +5 -4
- data/lib/renogen/extraction_stratagies/yaml_file/reader.rb +20 -11
- data/lib/renogen/formatters.rb +2 -0
- data/lib/renogen/formatters/base.rb +32 -7
- data/lib/renogen/formatters/csv.rb +42 -0
- data/lib/renogen/formatters/html.rb +1 -1
- data/lib/renogen/formatters/markdown.rb +2 -2
- data/lib/renogen/formatters/markdown_table.rb +58 -0
- data/lib/renogen/generator.rb +9 -1
- data/lib/renogen/version.rb +1 -1
- data/lib/renogen/writers/csv.rb +23 -0
- data/spec/lib/renogen/change_log/item_spec.rb +1 -1
- data/spec/lib/renogen/change_log/model_spec.rb +22 -8
- data/spec/lib/renogen/change_log/validator_spec.rb +38 -0
- data/spec/lib/renogen/change_log/writer_spec.rb +141 -2
- data/spec/lib/renogen/config_spec.rb +7 -2
- data/spec/lib/renogen/exceptions/invalid_item_found_spec.rb +35 -0
- data/spec/lib/renogen/exceptions/stratagy_not_found_spec.rb +2 -1
- data/spec/lib/renogen/{extraction_stratagies/yaml_file/exceptions → exceptions}/yaml_file_blank_spec.rb +1 -1
- data/spec/lib/renogen/exceptions/yaml_file_invalid_spec.rb +12 -0
- data/spec/lib/renogen/extraction_stratagies/yaml_file/parser_spec.rb +3 -3
- data/spec/lib/renogen/extraction_stratagies/yaml_file/reader_spec.rb +11 -5
- data/spec/lib/renogen/formatters/base_spec.rb +14 -4
- data/spec/lib/renogen/formatters/csv_spec.rb +49 -0
- data/spec/lib/renogen/formatters/html_spec.rb +1 -1
- data/spec/lib/renogen/formatters/markdown_spec.rb +2 -2
- data/spec/spec_helper.rb +5 -0
- data/spec/support/renogen_helper.rb +9 -0
- metadata +21 -12
- data/lib/renogen/extraction_stratagies/yaml_file/exceptions.rb +0 -12
- data/lib/renogen/extraction_stratagies/yaml_file/exceptions/yaml_file_blank.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3f61827e5a1a1224d86a20cddecf5757ace8719f2c6e38120e859f8951289814
|
4
|
+
data.tar.gz: f1174f4d416402cbf025a5a05f3f2f5ca00c436cecc032c6b87399dac7422bed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6683b5861e4d779967bf100a6683be6c6dccfe64e099906f6991caa266e5a976601c96a9905d8e89d91d2a958190301b3d7c54f79e7a644ff27319f8f50da926
|
7
|
+
data.tar.gz: aebbc3dcdf470a7882cf2c038406085d9233774f828675a7b5c0e787899c5be6ccb297419c9a82d92e9e64d172a73dcc71f2a6258aedf893c9dd8e16adbbec3e
|
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
|
-
|
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
|
-
|
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
|
-
|
43
|
+
```bash
|
44
|
+
$ docker run --rm -v `pwd`/.renogen:/.renogen:ro -v `pwd`/change_log:/change_log/ ddazza/renogen <CMD>
|
45
|
+
```
|
12
46
|
|
13
|
-
`
|
47
|
+
Now, you may initialize your repository with a `change_log` directory and a basic `.renogen` config file:
|
14
48
|
|
15
|
-
|
16
|
-
|
49
|
+
```
|
50
|
+
$ renogen init` # optional Creates directory for notes
|
51
|
+
```
|
17
52
|
|
18
|
-
|
53
|
+
<a name="Usage"></a>
|
54
|
+
## Usage
|
19
55
|
|
20
56
|
To generate your notes run the following command
|
21
57
|
|
22
|
-
|
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
|
-
|
65
|
+
```
|
66
|
+
$ renogen --help # list available command options
|
67
|
+
```
|
68
|
+
|
69
|
+
### Adding YAML feature notes
|
28
70
|
|
29
|
-
|
71
|
+
You can create a new file within the 'next' version folder (default: `change_log/next/`) manually:
|
30
72
|
|
31
|
-
|
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
|
-
|
96
|
+
You can also use the `new` command to create a feature note YAML file in the 'next' version folder:
|
56
97
|
|
57
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
167
|
+
```ruby
|
168
|
+
require 'renogen/formatters'
|
70
169
|
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
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
|
data/lib/renogen/change_log.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/renogen/cli.rb
CHANGED
@@ -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'] ||
|
17
|
-
source = options['source'] ||
|
18
|
-
options['changelog_path'] ||=
|
19
|
-
options['old_version'] ||=
|
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
|
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(
|
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(
|
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
|