This is an automated email from the ASF dual-hosted git repository.
sebb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/whimsy.git
The following commit(s) were added to refs/heads/master by this push:
new d357e02c Rework svn log parsing and pubsub messaging
d357e02c is described below
commit d357e02ca83b01066b0161a52310b8217613a462
Author: Sebb <[email protected]>
AuthorDate: Tue Mar 5 23:13:20 2024 +0000
Rework svn log parsing and pubsub messaging
---
lib/whimsy/asf/svn.rb | 51 +++++++++++++++++++++++++++++++---
tools/pubsub-ci-email.rb | 72 +++++++++++++++++++++++++++++++-----------------
2 files changed, 93 insertions(+), 30 deletions(-)
diff --git a/lib/whimsy/asf/svn.rb b/lib/whimsy/asf/svn.rb
index ba5cbc27..9f3396a5 100644
--- a/lib/whimsy/asf/svn.rb
+++ b/lib/whimsy/asf/svn.rb
@@ -437,14 +437,57 @@ module ASF
return out, err
end
+ DELIM =
'------------------------------------------------------------------------'
+ # parse commit log (non-xml)
+ # Return:
+ # Array of hash entries with keys: :revision, :author, :date, :msg
+ # The :msg entry will be missing if the quiet log option was used
+ # Note: parsing XML output proved somewhat slower
+ def self._parse_commits(src)
+ out = []
+ state = 0
+ linect = ent = msg = nil # ensure visibility
+ src.split(%r{\R}).each do |l|
+ case state
+ when 0 # start of block, should be delim
+ if l == DELIM
+ state = 1
+ ent = {}
+ else
+ raise ArgumentError.new "Unexpected line: '#{l}'"
+ end
+ when 1 # header line
+ revision, author, date, lines = l.split(' | ')
+ ent = {revision: revision, author: author, date: date}
+ if lines =~ %r{^(\d+) lines?} # There are some log lines
+ linect = $1.to_i + 3 # Allow for delim, header and blank line
+ msg = [] # collect the log message lines here
+ state += 1 # get ready to collect log lines
+ else # no log lines provided, we are done
+ out << ent
+ state = 0
+ end
+ else # collecting log lines
+ state += 1
+ msg << l if state > 3 # skip the blank line
+ if state == linect # we have read all the lines
+ ent[:msg] = msg.join("\n")
+ out << ent
+ state = 0
+ end
+ end
+ end
+ out
+ end
+
# get list of commmits from initial to current, and parses the output
# Returns: [out, err], where:
- # out = array of entries, each of which is an array of [commitid,
committer, datestamp]
+ # out = array of entries, each of which is a hash
# err = error message (in which case out is nil)
def self.svn_commits(path, before, after, options = {})
- out, err = ASF::SVN.svn('log', path, options.merge({quiet: true,
revision: "#{before}:#{after}"}))
- # extract lines starting with r1234, and split into fields
- return out&.scan(%r{^r\d+ .*})&.map {|k| k.split(' | ')}, err
+ out, err = ASF::SVN.svn('log', path, options.merge({revision:
"#{before}:#{after}"}))
+ out = _parse_commits(out) if out
+ return out, err
end
# as for self.svn_commits, but failure raises an error
diff --git a/tools/pubsub-ci-email.rb b/tools/pubsub-ci-email.rb
index 25be5102..56b82515 100755
--- a/tools/pubsub-ci-email.rb
+++ b/tools/pubsub-ci-email.rb
@@ -128,36 +128,56 @@ def parse_content(content)
}.to_h
end
-# Compare files. initial and current are arrays: [rev,commiter,date]
-def do_diff(initiala, currenta)
- initial = initiala[0]
- current = currenta[0]
- puts "Comparing #{initial} with #{current}"
- before = parse_content(fetch_revision(initial))
- after = parse_content(fetch_revision(current))
- puts "No changes detected" if before == after
+# Compare files. parameters are hashes.
+def do_diff(initialhash, currenthash)
+ initialrev = initialhash[:revision]
+ # initialcommitter = initialhash[:author]
+ # initialdate = initialhash[:date]
+ currentrev = currenthash[:revision]
+ currentcommitter = currenthash[:author]
+ currentdate = currenthash[:date]
+ commit_msg = currenthash[:msg]
+ currentcommittername = ASF::Person.find(currentcommitter).public_name
+ puts stamp "Comparing #{initialrev} with #{currentrev}"
+ before = parse_content(fetch_revision(initialrev))
+ after = parse_content(fetch_revision(currentrev))
+ if before == after
+ puts stamp "No changes detected"
+ else
+ puts stamp "Analysing changes"
+ end
+ # N.B. before/after are hashes: committee_name => {roster hash}
ASFJSON.cmphash(before, after) do |bc, type, key, args|
- id = bc[1]
- next unless id
- cttee = ASF::Committee.find(id)
+ # bc = breadcrumb, type = Added/Dropped, key = committeename, args =
individual roster entry
+ pmcid = bc[1]
+ next unless pmcid
+ cttee = ASF::Committee.find(pmcid)
+ ctteename = cttee.display_name
+ userid = key
+ username = args[:name]
+ joindate = args[:date]
mail_list = "private@#{cttee.mail_list}.apache.org"
- subject = "[TEST][NOTICE] #{args[:name]} (#{key}) #{TYPES[type] || type}
#{cttee.display_name} in #{current}"
+ change_text = TYPES[type] || type # 'added to|dropped from'
+ subject = "[TEST][NOTICE] #{username} (#{userid}) #{change_text}
#{ctteename} in #{currentrev}"
to = "[email protected],#{mail_list}"
body = <<~EOD
This is a TEST email
====================
To: [email protected],#{mail_list}
- Commit #{current} by #{currenta[1]} at #{currenta[2]}
- resulted in the following change:
-
- #{args[:name]} (#{key}) #{TYPES[type] || type} #{cttee.display_name}
- Joining date: #{args[:date]}
+ On #{currentdate} #{username} (#{userid}) was #{change_text} to the
+ #{ctteename} PMC by #{currentcommittername} (#{currentcommitter}).
+
+ The commit message was:
+ #{commit_msg}
+
+ Links for convenience:
+ https://svn.apache.org/repos/private/committers/board/committee-info.txt
(#{currentrev})
+ https://lists.apache.org/list?#{mail_list}
+ https://whimsy.apache.org/roster/committee/#{cttee.name}
+
+ This is an automated email generated by Whimsy (#{File.basename(__FILE__)})
- This is in comparison with the previous commit:
- #{initial} by #{initiala[1]} at #{initiala[2]}
-
- Generated by: #{__FILE__}
EOD
mail = Mail.new do
from "[email protected]" # TODO is this correct?
@@ -176,15 +196,15 @@ def handle_change(revision)
# get the last known revision
begin
previous_revision = File.read(PREVIOUS_REVISION).chomp
- puts "Detected last known revision '#{previous_revision}'"
+ puts stamp "Detected last known revision '#{previous_revision}'"
# get list of commmits from initial to current.
# @return array of entries, each of which is an array of [commitid,
committer, datestamp]
out,_ = ASF::SVN.svn_commits!(SOURCE_URL, previous_revision, revision)
- puts "No changes found since then" if out.size <= 1
+ puts stamp "Number of commits found since then: #{out.size - 1}"
# Get pairs of entries and calculate differences
out.each_cons(2) do |before, after|
do_diff(before, after)
- File.write(PREVIOUS_REVISION, after[0]) # done that one
+ # File.write(PREVIOUS_REVISION, after[0]) # done that one
end
rescue StandardError => e
raise e
@@ -205,6 +225,8 @@ end
if $0 == __FILE__
$stdout.sync = true
+ ASF::Mail.configure
+
if ARGV.delete('--testchange')
handle_change (ARGV.shift or raise "Need change id")
exit
@@ -212,8 +234,6 @@ if $0 == __FILE__
puts stamp "Starting #{File.basename(__FILE__)}"
- ASF::Mail.configure
-
# show initial start
previous_revision = File.read(PREVIOUS_REVISION).chomp.sub('r','').to_i