easy_changelog 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +23 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +0 -2
- data/lib/easy_changelog/configuration.rb +38 -6
- data/lib/easy_changelog/entry.rb +11 -0
- data/lib/easy_changelog/tasks/changelog.rake +9 -1
- data/lib/easy_changelog/version.rb +1 -1
- data/lib/easy_changelog.rb +49 -7
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 21835b5eb789e18516da3e0999774650180baa9fa09dcc6c5673089b179d2ce9
|
|
4
|
+
data.tar.gz: 4bbdd3915868d1795114f24139af6989e6d0a24b636ae0eb7b3b5ed2f5e90cf1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: deb7ac871213f284a3d3e99fff0b20172038b6e946b96d6f0b2d076599673c21df58330841c96925f985a7992fb4ae6e78fd85e4e5a5f8ccde7d5e09039ca4a9
|
|
7
|
+
data.tar.gz: 5130b516e4e1207bac5dc5b7be5e05d3279dd03aa94e106d44ce8b7b28446385b9fcfcfd9b263f4a9a93129cf29e939b6c5cc3499af3af5125d580ab107847c0
|
data/.rubocop.yml
CHANGED
|
@@ -2,6 +2,29 @@ AllCops:
|
|
|
2
2
|
TargetRubyVersion: 2.6
|
|
3
3
|
NewCops: enable
|
|
4
4
|
|
|
5
|
+
Lint/EmptyBlock:
|
|
6
|
+
Exclude:
|
|
7
|
+
- 'lib/easy_changelog/task_options_parser.rb'
|
|
8
|
+
Metrics/AbcSize:
|
|
9
|
+
Exclude:
|
|
10
|
+
- 'lib/easy_changelog/task_options_parser.rb'
|
|
11
|
+
|
|
12
|
+
Metrics/BlockLength:
|
|
13
|
+
Exclude:
|
|
14
|
+
- 'lib/easy_changelog/tasks/changelog.rake'
|
|
15
|
+
|
|
16
|
+
Metrics/ClassLength:
|
|
17
|
+
Enabled: false
|
|
18
|
+
|
|
19
|
+
Metrics/MethodLength:
|
|
20
|
+
Exclude:
|
|
21
|
+
- 'lib/easy_changelog/configuration.rb'
|
|
22
|
+
- 'lib/easy_changelog/task_options_parser.rb'
|
|
23
|
+
|
|
24
|
+
Metrics/ParameterLists:
|
|
25
|
+
Exclude:
|
|
26
|
+
- 'lib/easy_changelog/entry.rb'
|
|
27
|
+
|
|
5
28
|
Style/Documentation:
|
|
6
29
|
Enabled: false
|
|
7
30
|
|
data/CHANGELOG.md
CHANGED
|
@@ -5,3 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
* [#b0faf01](https://github.com/ivan05almeida/easy_changelog/commit/b0faf01): Initialize EasyChangelog gem. ([@ivan05almeida][])
|
|
7
7
|
* [#1763186](https://github.com/ivan05almeida/easy_changelog/commit/1763186): Update Readme. ([@ivan05almeida][])
|
|
8
|
+
* [#bec422a](https://github.com/ivan05almeida/easy_changelog/commit/bec422a): Automate release changelog entries. ([@ivan05almeida][])
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2025-01-16
|
|
11
|
+
|
|
12
|
+
- Initial release
|
|
13
|
+
[@ivan05almeida]: https://github.com/ivan05almeida
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'dotenv/load'
|
|
4
|
+
require 'date'
|
|
4
5
|
|
|
5
6
|
class EasyChangelog
|
|
6
7
|
class Configuration
|
|
7
|
-
attr_accessor :changelog_filename, :main_branch, :filename_max_length, :include_empty_task_id, :tasks_url
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
attr_accessor :changelog_filename, :main_branch, :filename_max_length, :include_empty_task_id, :tasks_url,
|
|
9
|
+
:task_id_sanitizer
|
|
10
|
+
attr_reader :entries_path, :unreleased_header, :entry_path_format, :user_signature, :type_mapping, :task_id_regex
|
|
11
|
+
attr_writer :repo_url, :release_message_template
|
|
10
12
|
|
|
11
13
|
def initialize
|
|
12
14
|
@entries_path = 'changelog/'
|
|
@@ -14,15 +16,21 @@ class EasyChangelog
|
|
|
14
16
|
|
|
15
17
|
@main_branch = 'master'
|
|
16
18
|
@entry_path_format = '<type>_<name>_<timestamp>.md'
|
|
17
|
-
@unreleased_header =
|
|
19
|
+
@unreleased_header = /## #{Regexp.escape("#{@main_branch} (unreleased)")}/m
|
|
18
20
|
@user_signature = Regexp.new(format(Regexp.escape('[@%<user>s][]'), user: '([\w-]+)'))
|
|
19
21
|
|
|
20
22
|
@filename_max_length = 50
|
|
21
|
-
@type_mapping = {
|
|
23
|
+
@type_mapping = {
|
|
24
|
+
breaking: { title: 'Breaking Changes', level: :major },
|
|
25
|
+
new: { title: 'New features', level: :minor },
|
|
26
|
+
fix: { title: 'Bug fixes', level: :patch }
|
|
27
|
+
}
|
|
22
28
|
@include_empty_task_id = false
|
|
23
29
|
|
|
24
30
|
@repo_url = ENV.fetch('REPOSITORY_URL', nil)
|
|
25
31
|
@tasks_url = ENV.fetch('TASKS_URL', nil)
|
|
32
|
+
@task_id_regex = %r{(?<task_id>[^/]+)/(?:.+)}
|
|
33
|
+
@release_message_template = -> { "## #{EasyChangelog::VERSION} (#{Date.today.iso8601})" }
|
|
26
34
|
end
|
|
27
35
|
|
|
28
36
|
def repo_url
|
|
@@ -31,8 +39,24 @@ class EasyChangelog
|
|
|
31
39
|
@repo_url
|
|
32
40
|
end
|
|
33
41
|
|
|
42
|
+
def release_message_template
|
|
43
|
+
raise ConfigurationError, 'release_message_template must be set' unless @release_message_template
|
|
44
|
+
|
|
45
|
+
return @release_message_template unless @release_message_template.respond_to?(:call)
|
|
46
|
+
|
|
47
|
+
message = @release_message_template.call
|
|
48
|
+
message = "## #{message}" unless message.start_with?('## ')
|
|
49
|
+
message
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def task_id_regex=(value)
|
|
53
|
+
raise ArgumentError, 'task_id_regex must be a Regexp' unless value.is_a?(Regexp)
|
|
54
|
+
|
|
55
|
+
@task_id_regex = value
|
|
56
|
+
end
|
|
57
|
+
|
|
34
58
|
def unreleased_header=(value)
|
|
35
|
-
@unreleased_header =
|
|
59
|
+
@unreleased_header = /## #{Regexp.escape(value)}/m
|
|
36
60
|
end
|
|
37
61
|
|
|
38
62
|
def entries_path=(value)
|
|
@@ -57,6 +81,14 @@ class EasyChangelog
|
|
|
57
81
|
@type_mapping.keys
|
|
58
82
|
end
|
|
59
83
|
|
|
84
|
+
def sections
|
|
85
|
+
@type_mapping.values.map { |v| v[:title] }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def section_for(type)
|
|
89
|
+
@type_mapping[type][:title]
|
|
90
|
+
end
|
|
91
|
+
|
|
60
92
|
def entry_path_match_regexp
|
|
61
93
|
formula = @entry_path_format.gsub(/<(\w+)>/) do |match|
|
|
62
94
|
matcher = match == '<type>' ? '[^_]' : '.'
|
data/lib/easy_changelog/entry.rb
CHANGED
|
@@ -7,6 +7,8 @@ class EasyChangelog
|
|
|
7
7
|
id, body = extract_id(body)
|
|
8
8
|
ref_id ||= id || last_commit_id
|
|
9
9
|
ref_type ||= id ? :pull : :commit
|
|
10
|
+
task_id ||= discover_task_id
|
|
11
|
+
|
|
10
12
|
super
|
|
11
13
|
end
|
|
12
14
|
|
|
@@ -56,6 +58,15 @@ class EasyChangelog
|
|
|
56
58
|
`git log -n1 --format="%h"`.chomp
|
|
57
59
|
end
|
|
58
60
|
|
|
61
|
+
def discover_task_id
|
|
62
|
+
return if EasyChangelog.configuration.task_id_regex.nil?
|
|
63
|
+
|
|
64
|
+
branch_name = `git rev-parse --abbrev-ref HEAD`
|
|
65
|
+
return if branch_name == EasyChangelog.configuration.main_branch
|
|
66
|
+
|
|
67
|
+
EasyChangelog.configuration.task_id_regex.match(branch_name)&.named_captures&.fetch('task_id', nil)
|
|
68
|
+
end
|
|
69
|
+
|
|
59
70
|
def extract_id(body)
|
|
60
71
|
/^\[Fix(?:es)? #(\d+)\] (.*)/.match(body)&.captures || [nil, body]
|
|
61
72
|
end
|
|
@@ -22,7 +22,7 @@ namespace :changelog do
|
|
|
22
22
|
task :merge do
|
|
23
23
|
raise 'No entries!' unless EasyChangelog.pending?
|
|
24
24
|
|
|
25
|
-
EasyChangelog.
|
|
25
|
+
EasyChangelog.merge_and_delete!
|
|
26
26
|
cmd = "git commit -a -m 'Update Changelog'"
|
|
27
27
|
puts cmd
|
|
28
28
|
sh cmd
|
|
@@ -36,4 +36,12 @@ namespace :changelog do
|
|
|
36
36
|
puts 'Do `bundle exec rake changelog:merge`'
|
|
37
37
|
exit(1)
|
|
38
38
|
end
|
|
39
|
+
|
|
40
|
+
desc 'Add release entry'
|
|
41
|
+
task :release do
|
|
42
|
+
EasyChangelog.release!
|
|
43
|
+
cmd = "git commit -a -m 'Update Changelog'"
|
|
44
|
+
puts cmd
|
|
45
|
+
sh cmd
|
|
46
|
+
end
|
|
39
47
|
end
|
data/lib/easy_changelog.rb
CHANGED
|
@@ -11,6 +11,7 @@ class EasyChangelog
|
|
|
11
11
|
|
|
12
12
|
class Error < StandardError; end
|
|
13
13
|
class ConfigurationError < StandardError; end
|
|
14
|
+
class EmptyReleaseError < StandardError; end
|
|
14
15
|
|
|
15
16
|
require 'easy_changelog/railtie' if defined?(Rails)
|
|
16
17
|
|
|
@@ -27,6 +28,14 @@ class EasyChangelog
|
|
|
27
28
|
entry_paths.any?
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
def merge_and_delete!
|
|
32
|
+
new.merge_and_delete!
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def release!
|
|
36
|
+
new.release!
|
|
37
|
+
end
|
|
38
|
+
|
|
30
39
|
def entry_paths
|
|
31
40
|
Dir["#{EasyChangelog.configuration.entries_path}*"]
|
|
32
41
|
end
|
|
@@ -36,15 +45,19 @@ class EasyChangelog
|
|
|
36
45
|
end
|
|
37
46
|
end
|
|
38
47
|
|
|
39
|
-
|
|
48
|
+
attr_reader :header, :entries
|
|
49
|
+
|
|
50
|
+
def initialize(content: File.read(EasyChangelog.configuration.changelog_filename),
|
|
51
|
+
entries: EasyChangelog.read_entries)
|
|
40
52
|
require 'strscan'
|
|
41
53
|
|
|
42
54
|
parse(content)
|
|
43
55
|
@entries = entries
|
|
44
56
|
end
|
|
45
57
|
|
|
46
|
-
def
|
|
47
|
-
|
|
58
|
+
def merge_and_delete!
|
|
59
|
+
merge!
|
|
60
|
+
delete!
|
|
48
61
|
end
|
|
49
62
|
|
|
50
63
|
def merge!
|
|
@@ -52,6 +65,15 @@ class EasyChangelog
|
|
|
52
65
|
self
|
|
53
66
|
end
|
|
54
67
|
|
|
68
|
+
def delete!
|
|
69
|
+
@entries.each_key { |path| File.delete(path) }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def release!
|
|
73
|
+
File.write(EasyChangelog.configuration.changelog_filename, release_content)
|
|
74
|
+
self
|
|
75
|
+
end
|
|
76
|
+
|
|
55
77
|
def unreleased_content
|
|
56
78
|
entry_map = parse_entries(@entries)
|
|
57
79
|
merged_map = merge_entries(entry_map)
|
|
@@ -64,7 +86,20 @@ class EasyChangelog
|
|
|
64
86
|
merged_content << EOF
|
|
65
87
|
end
|
|
66
88
|
|
|
89
|
+
def release_content
|
|
90
|
+
unreleased = unreleased_content
|
|
91
|
+
raise EmptyReleaseError, 'No unreleased content to release' if unreleased.empty?
|
|
92
|
+
|
|
93
|
+
release_message = EasyChangelog.configuration.release_message_template
|
|
94
|
+
release_message = "\n#{release_message}" unless release_message.start_with?("\n")
|
|
95
|
+
|
|
96
|
+
released_content = [@header, release_message, unreleased, @rest.chomp, *new_contributor_lines].join("\n")
|
|
97
|
+
released_content << EOF
|
|
98
|
+
end
|
|
99
|
+
|
|
67
100
|
def new_contributor_lines
|
|
101
|
+
return [] unless EasyChangelog.configuration.user_signature
|
|
102
|
+
|
|
68
103
|
unique_contributor_names = contributors.map { |user| format(CONTRIBUTOR, user: user) }.uniq
|
|
69
104
|
|
|
70
105
|
unique_contributor_names.reject { |line| @rest.include?(line) }
|
|
@@ -82,7 +117,7 @@ class EasyChangelog
|
|
|
82
117
|
|
|
83
118
|
def merge_entries(entry_map)
|
|
84
119
|
all = @unreleased.merge(entry_map) { |_k, v1, v2| v1.concat(v2) }
|
|
85
|
-
canonical = EasyChangelog.configuration.
|
|
120
|
+
canonical = EasyChangelog.configuration.sections.to_h { |v| [v, nil] }
|
|
86
121
|
canonical.merge(all).compact
|
|
87
122
|
end
|
|
88
123
|
|
|
@@ -90,8 +125,15 @@ class EasyChangelog
|
|
|
90
125
|
ss = StringScanner.new(content)
|
|
91
126
|
|
|
92
127
|
@header = ss.scan_until(EasyChangelog.configuration.unreleased_header)
|
|
93
|
-
|
|
94
|
-
|
|
128
|
+
unreleased = ss.scan_until(/\n(?=## )/m)
|
|
129
|
+
|
|
130
|
+
if unreleased
|
|
131
|
+
@unreleased = parse_release(unreleased)
|
|
132
|
+
@rest = ss.rest
|
|
133
|
+
else
|
|
134
|
+
@unreleased = parse_release(ss.rest)
|
|
135
|
+
@rest = ''
|
|
136
|
+
end
|
|
95
137
|
end
|
|
96
138
|
|
|
97
139
|
# @return [Hash<type, Array<String>]]
|
|
@@ -110,7 +152,7 @@ class EasyChangelog
|
|
|
110
152
|
changes = Hash.new { |h, k| h[k] = [] }
|
|
111
153
|
|
|
112
154
|
path_content_map.each do |path, content|
|
|
113
|
-
header = EasyChangelog.configuration.
|
|
155
|
+
header = EasyChangelog.configuration.section_for(entry_type(path))
|
|
114
156
|
|
|
115
157
|
changes[header].concat(content.lines.map(&:chomp))
|
|
116
158
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: easy_changelog
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ivan de Paula Almeida Filho
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-01-
|
|
11
|
+
date: 2025-01-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Changelog generator, based on Rubocop contributing section.
|
|
14
14
|
email:
|