release-notes 2.0.0 → 3.0.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/.travis.yml +0 -1
- data/CHANGELOG.md +57 -43
- data/CODE_OF_CONDUCT.md +1 -1
- data/LICENSE.txt +1 -1
- data/lib/release/notes.rb +13 -6
- data/lib/release/notes/commits.rb +141 -0
- data/lib/release/notes/configurable.rb +16 -0
- data/lib/release/notes/date_formatter.rb +31 -0
- data/lib/release/notes/git.rb +60 -25
- data/lib/release/notes/link.rb +55 -13
- data/lib/release/notes/log.rb +71 -103
- data/lib/release/notes/prettify.rb +39 -0
- data/lib/release/notes/system.rb +58 -25
- data/lib/release/notes/tag.rb +152 -0
- data/lib/release/notes/version.rb +1 -1
- data/lib/release/notes/write.rb +86 -30
- metadata +7 -4
- data/lib/release/notes/date_format.rb +0 -19
- data/lib/release/notes/pretty_print.rb +0 -24
data/lib/release/notes/git.rb
CHANGED
@@ -2,41 +2,76 @@
|
|
2
2
|
|
3
3
|
module Release
|
4
4
|
module Notes
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
included do
|
11
|
-
delegate :all_labels, :grep_insensitive?,
|
12
|
-
:regex_type, :include_merges?, to: :"Release::Notes.configuration"
|
5
|
+
class Git
|
6
|
+
class << self
|
7
|
+
include Configurable
|
8
|
+
DEFAULT_TAG = "HEAD"
|
13
9
|
|
10
|
+
#
|
11
|
+
# Returns a string matching the following format: "hash - message\n"
|
12
|
+
# for all commits falling within the tag_from and tag_to threshold
|
13
|
+
# taking account the relevant label, invert grep options, and log format
|
14
|
+
#
|
15
|
+
# @param **opts
|
16
|
+
#
|
17
|
+
# @return [String] git log entries between tag_from and tag_to that include the word(s) in label,
|
18
|
+
# taking into account the invert grep and log_format flags specified.
|
19
|
+
#
|
14
20
|
def log(**opts)
|
15
21
|
"git log '#{opts[:tag_from]}'..'#{opts[:tag_to]}'" \
|
16
22
|
" --grep='#{opts[:label]}#{opts[:invert_grep]}'" \
|
17
|
-
" #{
|
18
|
-
" #{
|
23
|
+
" #{config_regex_type} #{config_grep_insensitive?}" \
|
24
|
+
" #{config_include_merges?} --format='%h #{log_format}'"
|
19
25
|
end
|
20
|
-
end
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
|
27
|
+
#
|
28
|
+
# Returns the git hash of the first commit.
|
29
|
+
#
|
30
|
+
# @return [String] the first commit hash.
|
31
|
+
#
|
32
|
+
def first_commit
|
33
|
+
"git rev-list --max-parents=0 #{DEFAULT_TAG}"
|
34
|
+
end
|
25
35
|
|
26
|
-
|
27
|
-
|
28
|
-
|
36
|
+
#
|
37
|
+
# Returns the latest git tag.
|
38
|
+
#
|
39
|
+
# @return [String] the most recent tag.
|
40
|
+
#
|
41
|
+
def last_tag
|
42
|
+
"git describe --abbrev=0 --tags"
|
43
|
+
end
|
29
44
|
|
30
|
-
|
31
|
-
|
32
|
-
|
45
|
+
#
|
46
|
+
# Returns the date and time of the latest tag.
|
47
|
+
#
|
48
|
+
# @param [String] a git tag
|
49
|
+
#
|
50
|
+
# @return [String] the most recent tag date.
|
51
|
+
#
|
52
|
+
def tag_date(tag)
|
53
|
+
"git log -1 --format=%ai #{tag}"
|
54
|
+
end
|
33
55
|
|
34
|
-
|
35
|
-
|
36
|
-
|
56
|
+
#
|
57
|
+
# Returns an array of all tags in the git log
|
58
|
+
#
|
59
|
+
# @return [Array] all git tags
|
60
|
+
#
|
61
|
+
def read_all_tags
|
62
|
+
"git for-each-ref --sort=taggerdate --format='%(tag)' refs/tags"
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
37
66
|
|
38
|
-
|
39
|
-
|
67
|
+
#
|
68
|
+
# Returns a string representing the git log format flag
|
69
|
+
#
|
70
|
+
# @return [String] git log format flag
|
71
|
+
#
|
72
|
+
def log_format
|
73
|
+
"- %s"
|
74
|
+
end
|
40
75
|
end
|
41
76
|
end
|
42
77
|
end
|
data/lib/release/notes/link.rb
CHANGED
@@ -6,8 +6,15 @@ module Release
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
|
9
|
+
include Configurable
|
10
10
|
|
11
|
+
#
|
12
|
+
# Link log messages
|
13
|
+
#
|
14
|
+
# @param [String] lines - log messages for a git tag
|
15
|
+
#
|
16
|
+
# @return [String] log messages that can be linked
|
17
|
+
#
|
11
18
|
def link_lines(lines:)
|
12
19
|
@new_lines = ""
|
13
20
|
split_lines(lines)
|
@@ -16,33 +23,59 @@ module Release
|
|
16
23
|
|
17
24
|
private
|
18
25
|
|
19
|
-
#
|
26
|
+
#
|
27
|
+
# Format lines or add link if log message should be linked
|
28
|
+
#
|
29
|
+
# @param [String] lines - log messages for a given git commit
|
30
|
+
#
|
31
|
+
# @return [Array] label log messages should be linked to
|
32
|
+
#
|
20
33
|
def split_lines(lines)
|
21
|
-
lines.split(
|
22
|
-
unless
|
23
|
-
@new_lines += "#{line}
|
34
|
+
lines.split(NEWLINE).each do |line|
|
35
|
+
unless config_link_to_labels&.any? { |la| line.include? la }
|
36
|
+
@new_lines += "#{line}#{NEWLINE}"
|
24
37
|
next
|
25
38
|
end
|
26
39
|
split_words(line)
|
27
40
|
end
|
28
41
|
end
|
29
42
|
|
30
|
-
#
|
43
|
+
#
|
44
|
+
# Determine if log message has a pre-determined label
|
45
|
+
#
|
46
|
+
# @param [String] line - a line from the log messages
|
47
|
+
#
|
48
|
+
# @return none
|
49
|
+
#
|
31
50
|
def split_words(line)
|
32
|
-
|
51
|
+
config_link_to_labels.each_with_index do |label, i|
|
33
52
|
next unless line.include? label
|
34
53
|
|
35
54
|
replace_lines(line, label, i)
|
36
55
|
end
|
37
56
|
end
|
38
57
|
|
39
|
-
#
|
58
|
+
#
|
59
|
+
# Replace a word in the changelog
|
60
|
+
#
|
61
|
+
# @param [String line - a line from the log messages
|
62
|
+
# @param [String] label - a specified label
|
63
|
+
# @param [Integer] index - index of log message
|
64
|
+
#
|
65
|
+
# @return none
|
66
|
+
#
|
40
67
|
def replace_lines(line, label, index)
|
41
68
|
replace_words(line.split(/\s/))
|
42
|
-
@new_lines += "#{replace(line, @word, label, index)}
|
69
|
+
@new_lines += "#{replace(line, @word, label, index)}#{NEWLINE}" if @word
|
43
70
|
end
|
44
71
|
|
45
|
-
#
|
72
|
+
#
|
73
|
+
# Replace words if log message
|
74
|
+
#
|
75
|
+
# @param [Array] words - split git log message
|
76
|
+
#
|
77
|
+
# @return [String] word to replace in the log message
|
78
|
+
#
|
46
79
|
def replace_words(words)
|
47
80
|
words.each do |word|
|
48
81
|
next unless (word =~ /^#.*/)&.zero?
|
@@ -51,11 +84,20 @@ module Release
|
|
51
84
|
end
|
52
85
|
end
|
53
86
|
|
54
|
-
#
|
87
|
+
#
|
88
|
+
# Replace log messages with linked messages
|
89
|
+
#
|
90
|
+
# @param [String] line - log message to replace
|
91
|
+
# @param [String] issue_number - word to replace
|
92
|
+
# @param [String] label - label to replace with
|
93
|
+
# @param [Integer] index - index of the linked site
|
94
|
+
#
|
95
|
+
# @return [String] formatted linked line
|
96
|
+
#
|
55
97
|
def replace(line, issue_number, label, index)
|
56
98
|
identifier = "#{label.split(/\s/)[0]} #{issue_number}"
|
57
|
-
humanized = "#{
|
58
|
-
linked = "[#{humanized}](#{
|
99
|
+
humanized = "#{config_link_to_humanize[index]} #{issue_number}"
|
100
|
+
linked = "[#{humanized}](#{config_link_to_sites[index]}\/#{issue_number.tr('^0-9', '')})"
|
59
101
|
|
60
102
|
line.gsub! identifier, linked
|
61
103
|
line
|
data/lib/release/notes/log.rb
CHANGED
@@ -3,140 +3,108 @@
|
|
3
3
|
module Release
|
4
4
|
module Notes
|
5
5
|
class Log
|
6
|
-
include
|
7
|
-
delegate :force_rewrite, :all_labels, :log_all, :header_title,
|
8
|
-
:header_title_type, :features, :bugs, :misc, :feature_title,
|
9
|
-
:bug_title, :misc_title, :log_all_title, :single_label,
|
10
|
-
:release_notes_exist?, to: :"Release::Notes.configuration"
|
11
|
-
|
12
|
-
delegate :date_humanized, :format_tag_date, to: :date_formatter
|
13
|
-
delegate :digest_header, :digest_title, to: :writer
|
14
|
-
|
15
|
-
def initialize
|
16
|
-
@_commits = []
|
17
|
-
end
|
6
|
+
include Configurable
|
18
7
|
|
8
|
+
#
|
9
|
+
# Release::Notes::Log initializer
|
10
|
+
#
|
11
|
+
# @return none
|
12
|
+
#
|
19
13
|
def perform
|
20
|
-
if
|
21
|
-
# Find the last tag and group all commits
|
22
|
-
# under a date header at the time this is run
|
23
|
-
find_last_tag_and_log
|
24
|
-
else
|
14
|
+
if log_from_start?
|
25
15
|
# Find all tags and get the logs between each tag
|
26
16
|
# run this the first time if nothing exists
|
27
17
|
find_all_tags_and_log_all
|
18
|
+
else
|
19
|
+
# Find the last tag and group all commits
|
20
|
+
# under a date header at the time this is run
|
21
|
+
find_last_tag_and_log
|
28
22
|
end
|
23
|
+
|
29
24
|
writer.write_new_file
|
30
25
|
end
|
31
26
|
|
32
27
|
private
|
33
28
|
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
return unless log_all
|
42
|
-
|
43
|
-
log = system_log(tag_from: tag_from, tag_to: tag_to)
|
44
|
-
log_grouped_commits(title: log_all_title, log: log)
|
45
|
-
end
|
46
|
-
|
47
|
-
# @api private
|
48
|
-
def date_formatter
|
49
|
-
@date_formatter ||= Release::Notes::DateFormat.new
|
50
|
-
end
|
51
|
-
|
52
|
-
# @api private
|
29
|
+
#
|
30
|
+
# Find the most recent git tag
|
31
|
+
#
|
32
|
+
# @return [Array] most recent git tag
|
33
|
+
#
|
53
34
|
def find_last_tag_and_log
|
54
|
-
last_tag
|
55
|
-
# return false unless system_log(tag_from: last_tag, label: all_labels).present?
|
56
|
-
if system_log(tag_from: last_tag, label: all_labels).blank?
|
57
|
-
log_last
|
58
|
-
return
|
59
|
-
end
|
60
|
-
# output the date right now
|
61
|
-
header_content date: date_humanized, tag: tag_to
|
62
|
-
copy_single_tag_of_activity(tag_from: last_tag)
|
35
|
+
tag_logger(System.last_tag.strip, previous_tag(0))
|
63
36
|
end
|
64
37
|
|
65
|
-
#
|
38
|
+
#
|
39
|
+
# Get all git tags and add to the changelog
|
40
|
+
#
|
41
|
+
# @return [Array] all the git tags
|
42
|
+
#
|
66
43
|
def find_all_tags_and_log_all
|
67
44
|
git_all_tags.each_with_index do |ta, i|
|
68
|
-
|
69
|
-
date: date_humanized(date: System.tag_date(tag: ta)),
|
70
|
-
tag: ta,
|
71
|
-
)
|
72
|
-
|
73
|
-
copy_single_tag_of_activity(
|
74
|
-
tag_from: previous_tag(i).strip,
|
75
|
-
tag_to: ta,
|
76
|
-
)
|
45
|
+
tag_logger(ta, previous_tag(i))
|
77
46
|
end
|
78
47
|
end
|
79
48
|
|
80
|
-
#
|
81
|
-
|
82
|
-
|
83
|
-
|
49
|
+
#
|
50
|
+
# Check whether to start from the beginning of the git log
|
51
|
+
#
|
52
|
+
# @return [Boolean] append to changelog or start from beginning of git log
|
53
|
+
#
|
54
|
+
def log_from_start?
|
55
|
+
!config_release_notes_exist? || config_force_rewrite
|
84
56
|
end
|
85
57
|
|
86
|
-
#
|
58
|
+
#
|
59
|
+
# All tags in the git log
|
60
|
+
#
|
61
|
+
# @return [Array] all git tags
|
62
|
+
#
|
87
63
|
def git_all_tags
|
88
|
-
@git_all_tags ||= System.all_tags.split(
|
89
|
-
end
|
90
|
-
|
91
|
-
# @api private
|
92
|
-
def header_content(**date_and_tag)
|
93
|
-
digest_header(date_and_tag[header_title_type.to_sym])
|
64
|
+
@git_all_tags ||= System.all_tags.split(NEWLINE).reverse
|
94
65
|
end
|
95
66
|
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
digest_unique_messages(log_messages, trimmed_commit_hashes, title) if trimmed_commit_hashes.present?
|
106
|
-
end
|
107
|
-
|
108
|
-
# @api private
|
109
|
-
def digest_unique_messages(log_messages, commit_hashes, title)
|
110
|
-
messages = log_messages.map do |msg|
|
111
|
-
msg[1..-1].join if commit_hashes.include?(msg[0].strip)
|
112
|
-
end.compact
|
113
|
-
|
114
|
-
@_commits += commit_hashes
|
115
|
-
|
116
|
-
digest_title(title: title, log_message: "#{messages.join("\n")}\n")
|
117
|
-
end
|
118
|
-
|
119
|
-
# @api private
|
120
|
-
def trim_commit_hashes(commit_hashes)
|
121
|
-
commit_hashes.dup.each do |commit|
|
122
|
-
commit_hashes.delete commit if single_label && @_commits.include?(commit)
|
123
|
-
end
|
124
|
-
commit_hashes
|
67
|
+
#
|
68
|
+
# Second to last tag in the git log
|
69
|
+
#
|
70
|
+
# @param [Integer] index - index of the git tags array
|
71
|
+
#
|
72
|
+
# @return [String] second most recent git tag
|
73
|
+
#
|
74
|
+
def previous_tag(index)
|
75
|
+
git_all_tags[index + 1].yield_self { |t| tag(t) }.strip
|
125
76
|
end
|
126
77
|
|
127
|
-
#
|
128
|
-
|
129
|
-
|
78
|
+
#
|
79
|
+
# Get the next git tag or the first tag
|
80
|
+
#
|
81
|
+
# @param [String] git_tag - a git tag
|
82
|
+
#
|
83
|
+
# @return [String] most recent git tag or the first git tag
|
84
|
+
#
|
85
|
+
def tag(git_tag)
|
86
|
+
git_tag.present? ? git_tag : System.first_commit
|
130
87
|
end
|
131
88
|
|
132
|
-
#
|
133
|
-
|
134
|
-
|
89
|
+
#
|
90
|
+
# Create a Release::Notes::Tag object
|
91
|
+
#
|
92
|
+
# @param [String] tag - tag to
|
93
|
+
# @param [String] previous_tag - tag from
|
94
|
+
#
|
95
|
+
# @return [Object] Release::Notes::Tag object
|
96
|
+
#
|
97
|
+
def tag_logger(tag, previous_tag)
|
98
|
+
Tag.new(tag: tag, previous_tag: previous_tag, writer: writer).perform
|
135
99
|
end
|
136
100
|
|
137
|
-
#
|
101
|
+
#
|
102
|
+
# Create write object containing the header, title, and log messages for a given tag
|
103
|
+
#
|
104
|
+
# @return [Object] Release::Notes::Write object
|
105
|
+
#
|
138
106
|
def writer
|
139
|
-
@writer ||=
|
107
|
+
@writer ||= Write.new
|
140
108
|
end
|
141
109
|
end
|
142
110
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Release
|
4
|
+
module Notes
|
5
|
+
class Prettify
|
6
|
+
include Configurable
|
7
|
+
attr_reader :line
|
8
|
+
|
9
|
+
#
|
10
|
+
# Release::Notes::Prettify initializer
|
11
|
+
#
|
12
|
+
# @param [String] line - a line from the git log
|
13
|
+
#
|
14
|
+
def initialize(line:)
|
15
|
+
@line = line
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Perform method for Release::Notes::Prettify
|
20
|
+
#
|
21
|
+
# @return [String] log message
|
22
|
+
#
|
23
|
+
def perform
|
24
|
+
line.gsub(labels_regex, "").strip
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
#
|
30
|
+
# Holds the regular expression used to match a pattern against labels
|
31
|
+
#
|
32
|
+
# @return [Regexp] regex containing all labels
|
33
|
+
#
|
34
|
+
def labels_regex
|
35
|
+
Regexp.new config_all_labels, Regexp::IGNORECASE
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|