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