Skip to content

Support ChangeLog generated by git log #787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions lib/rdoc/parser/changelog.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ def group_entries entries

def parse_entries
@time_cache ||= {}

if /\A((?:.*\n){,3})commit\s/ =~ @content
class << self; prepend Git; end
parse_info($1)
return parse_entries
end

entries = []
entry_name = nil
entry_body = []
Expand Down Expand Up @@ -190,6 +197,7 @@ def parse_entries

def scan
@time_cache = {}

entries = parse_entries
grouped_entries = group_entries entries

Expand All @@ -200,5 +208,120 @@ def scan
@top_level
end

module Git
def parse_info(info)
/^\s*base-url\s*=\s*(.*\S)/ =~ info
@base_url = $1
end

def parse_entries
entries = []

@content.scan(/^commit\s+(\h{20})\h*\n((?:.+\n)*)\n((?: {4}.*\n+)*)/) do
entry_name, header, entry_body = $1, $2, $3.gsub(/^ {4}/, '')
# header = header.scan(/^ *(\S+?): +(.*)/).to_h
# date = header["CommitDate"] || header["Date"]
date = header[/^ *(?:Author)?Date: +(.*)/, 1]
author = header[/^ *Author: +(.*)/, 1]
if /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+) *([-+]\d\d)(\d\d)/ =~
(header[/^ *CommitDate: +(.*)/, 1] || date)
time = Time.new($1, $2, $3, $4, $5, $6, "#{$7}:#{$8}")
@time_cache[entry_name] = time
author.sub!(/\s*<(.*)>/, '')
email = $1
entries << [entry_name, [author, email, date, entry_body]]
end
end

entries
end

def create_entries entries
# git log entries have no strictly itemized style like the old
# style, just assume Markdown.
entries.map do |commit, entry|
LogEntry.new(@base_url, commit, *entry)
end
end

LogEntry = Struct.new(:base, :commit, :author, :email, :date, :contents) do
HEADING_LEVEL = 3

def initialize(base, commit, author, email, date, contents)
case contents
when String
contents = RDoc::Markdown.parse(contents).parts.each do |body|
case body
when RDoc::Markup::Heading
body.level += HEADING_LEVEL + 1
end
end
case first = contents[0]
when RDoc::Markup::Paragraph
contents[0] = RDoc::Markup::Heading.new(HEADING_LEVEL + 1, first.text)
end
end
super
end

def level
HEADING_LEVEL
end

def aref
"label-#{commit}"
end

def label context = nil
aref
end

def text
case base
when nil
"#{date}"
when /%s/
"{#{date}}[#{base % commit}]"
else
"{#{date}}[#{base}#{commit}]"
end + " {#{author}}[mailto:#{email}]"
end

def accept visitor
visitor.accept_heading self
begin
if visitor.respond_to?(:code_object=)
code_object = visitor.code_object
visitor.code_object = self
end
contents.each do |body|
body.accept visitor
end
ensure
if visitor.respond_to?(:code_object)
visitor.code_object = code_object
end
end
end

def pretty_print q # :nodoc:
q.group(2, '[log_entry: ', ']') do
q.text commit
q.text ','
q.breakable
q.group(2, '[date: ', ']') { q.text date }
q.text ','
q.breakable
q.group(2, '[author: ', ']') { q.text author }
q.text ','
q.breakable
q.group(2, '[email: ', ']') { q.text email }
q.text ','
q.breakable
q.pp contents
end
end
end
end
end

132 changes: 132 additions & 0 deletions test/rdoc/test_rdoc_parser_changelog.rb
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,24 @@ def test_parse_entries_gnu
assert_equal expected, parser.parse_entries
end

def test_parse_entries_git
parser = util_parser <<-ChangeLog
commit\ 709bed2afaee50e2ce803f87bf1ee8291bea41e3
Author: git <[email protected]>
Date: 2021-01-21 01:03:52 +0900

* 2021-01-21 [ci skip]
ChangeLog

expected = [
[ "709bed2afaee50e2ce80",
[ "git", "[email protected]",
"2021-01-21 01:03:52 +0900",
"* 2021-01-21 [ci skip]\n"]]]

assert_equal expected, parser.parse_entries
end

def test_scan
parser = util_parser <<-ChangeLog
Tue Dec 4 08:32:10 2012 Eric Hodel <[email protected]>
Expand Down Expand Up @@ -309,10 +327,124 @@ def test_scan
assert_equal expected, @top_level.comment
end

def test_scan_git
parser = util_parser <<-ChangeLog
commit\ 709bed2afaee50e2ce803f87bf1ee8291bea41e3
Author: git <[email protected]>
Date: 2021-01-21 01:03:52 +0900

* 2021-01-21 [ci skip]

commit\ a8dc5156e183489c5121fb1759bda5d9406d9175
Author: git <[email protected]>
Date: 2021-01-20 01:58:26 +0900

* 2021-01-20 [ci skip]

commit\ de5f8a92d5001799bedb3b1a271a2d9b23c6c8fb
Author: Masataka Pocke Kuwabara <[email protected]>
Date: 2021-01-01 14:25:08 +0900

Make args info for RubyVM::AST to available on endless method without parens

Problem
===

Arguments information is missing for endless method without parens.
For example:

```ruby
# ok
```

It causes an error if a program expects `args` node exists.

Solution
===

Call `new_args` on this case.
ChangeLog

parser.scan

expected = doc(
head(1, File.basename(@tempfile.path)),
blank_line,
head(2, '2021-01-21'),
blank_line,
log_entry(nil, '709bed2afaee50e2ce80',
'git', '[email protected]', '2021-01-21 01:03:52 +0900',
[list(:BULLET, item(nil, para('2021-01-21 [ci skip]')))]),
head(2, '2021-01-20'),
blank_line,
log_entry(nil, 'a8dc5156e183489c5121',
'git', '[email protected]', '2021-01-20 01:58:26 +0900',
[list(:BULLET, item(nil, para('2021-01-20 [ci skip]')))]),
head(2, '2021-01-01'),
blank_line,
log_entry(nil, 'de5f8a92d5001799bedb',
'Masataka Pocke Kuwabara', '[email protected]', '2021-01-01 14:25:08 +0900',
[head(4, 'Make args info for RubyVM::AST to available on endless method without parens'),
head(5, 'Problem'),
para("Arguments information is missing for endless method without parens.\n" +
"For example:"),
verb("# ok\n").tap {|v| v.format = :ruby},
para('It causes an error if a program expects <code>args</code> node exists.'),
head(5, 'Solution'),
para('Call <code>new_args</code> on this case.')]))

expected.file = @top_level

assert_equal expected, @top_level.comment
end

def test_scan_git_commit_date
parser = util_parser <<-ChangeLog
commit\ ee1e690a2df901adb279d7a63fbd92c64e0a5ae6
Author: Igor Zubkov <[email protected]>
AuthorDate: 2016-10-25 03:56:11 +0900
Commit: Nobuyoshi Nakada <[email protected]>
CommitDate: 2021-01-07 13:40:42 +0900

We don't need "require 'uri'" after "require 'net/http'".

commit\ 4d0985a7bd8f591dff4b430e288bfd83af782e51
Author: git <[email protected]>
AuthorDate: 2021-01-07 10:21:34 +0900
Commit: git <[email protected]>
CommitDate: 2021-01-07 10:21:34 +0900

* 2021-01-07 [ci skip]
ChangeLog

parser.scan

expected = doc(
head(1, File.basename(@tempfile.path)),
blank_line,
head(2, "2021-01-07"),
blank_line,
log_entry(nil, 'ee1e690a2df901adb279',
'Igor Zubkov', '[email protected]',
'2016-10-25 03:56:11 +0900',
[head(4, %[We don't need "require 'uri'" after "require 'net/http'".])]),
log_entry(nil, '4d0985a7bd8f591dff4b',
'git', '[email protected]',
'2021-01-07 10:21:34 +0900',
[list(:BULLET, item(nil, para("2021-01-07 [ci skip]")))]))

expected.file = @top_level

assert_equal expected, @top_level.comment
end

def util_parser content = ''
RDoc::Parser::ChangeLog.new \
@top_level, @tempfile.path, content, @options, @stats
end

def log_entry(*a)
RDoc::Parser::ChangeLog::Git::LogEntry.new(*a)
end
end