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 <s...@apache.org>
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 = "bo...@apache.org,#{mail_list}"
     body = <<~EOD
     This is a TEST email
     ====================
     To: bo...@apache.org,#{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 "notificati...@whimsical.apache.org" # 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
 

Reply via email to