You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by ru...@apache.org on 2017/09/26 16:15:52 UTC

[whimsy] branch master updated: update code to process PMC resolutions

This is an automated email from the ASF dual-hosted git repository.

rubys 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 bd43869  update code to process PMC resolutions
bd43869 is described below

commit bd43869beac935626dba9cee5cf3b912dd1c191a
Author: Sam Ruby <ru...@intertwingly.net>
AuthorDate: Tue Sep 26 12:15:34 2017 -0400

    update code to process PMC resolutions
---
 lib/whimsy/asf/agenda/special.rb               |   8 +-
 lib/whimsy/asf/committee.rb                    |  36 +++--
 www/board/agenda/views/actions/todos.json.rb   | 186 ++++++++++++++++---------
 www/board/agenda/views/pages/adjournment.js.rb | 107 ++++++++------
 4 files changed, 210 insertions(+), 127 deletions(-)

diff --git a/lib/whimsy/asf/agenda/special.rb b/lib/whimsy/asf/agenda/special.rb
index 31a4064..858e48e 100644
--- a/lib/whimsy/asf/agenda/special.rb
+++ b/lib/whimsy/asf/agenda/special.rb
@@ -25,7 +25,13 @@ class ASF::Board::Agenda
       title.sub! /\sCommittee\s/, ' '
       title.sub! /\sProject(\s|$)/i, '\1'
       title.sub! /\sPMC(\s|$)/, '\1'
-      title.sub! /\s\(.*\)$/, ''
+
+      if title =~ /^Establish .* \((.*)\)$/
+        title.sub! /\s.*?\(/, ' '
+        title.sub! /\)$/, ''
+      else
+        title.sub! /\s\(.*\)$/, ''
+      end
 
       attrs['fulltitle'] = fulltitle if title != fulltitle
 
diff --git a/lib/whimsy/asf/committee.rb b/lib/whimsy/asf/committee.rb
index 9aa728c..25a179b 100644
--- a/lib/whimsy/asf/committee.rb
+++ b/lib/whimsy/asf/committee.rb
@@ -120,23 +120,23 @@ module ASF
 
       # update/remove existing 'missing' entries
       block.gsub! /(.*?)# missing in .*\n/ do |line|
-	if missing.include? $1.strip
-	  missing.delete $1.strip
-	  "#{line.chomp}, #{month}\n"
-	else
-	  ''
-	end
+        if missing.include? $1.strip
+          missing.delete $1.strip
+          "#{line.chomp}, #{month}\n"
+        else
+          ''
+        end
       end
 
       # add new 'missing' entries
       missing.each do |pmc|
-	block += "    #{pmc.ljust(22)} # missing in #{month}\n"
+        block += "    #{pmc.ljust(22)} # missing in #{month}\n"
       end
 
       # add new 'established' entries
       month = (date+91).strftime('%B')
       establish.each do |pmc|
-	block += "    #{pmc.ljust(22)} # new, monthly through #{month}\n"
+        block += "    #{pmc.ljust(22)} # new, monthly through #{month}\n"
       end
 
       # replace/append block
@@ -154,27 +154,25 @@ module ASF
     end
 
     # update chairs
-    def self.update_chairs(contents, establish, change, terminate)
+    def self.update_chairs(contents, establish_or_change, terminate)
       # extract committee section; and then extract the lines containing
       # committee names and chairs
       section = contents[/^1\..*?\n=+/m]
       committees = section[/-\n(.*?)\n\n/m, 1].scan(/^ +(.*?)  +(.*)/).to_h
 
       # update/add chairs based on establish and change resolutions
-      (establish.merge(change)).each do |name, chair|
-	person = ASF::Person.find(chair)
-	committees[name] = "#{person.public_name} <#{...@apache.org>"
+      establish_or_change.each do |name, chair|
+        person = ASF::Person.find(chair)
+        committees[name] = "#{person.public_name} <#{...@apache.org>"
       end
 
       # remove committees based on terminate resolutions
-      terminate.each do |name|
-	committees.delete(name)
-      end
+      terminate.each {|name| committees.delete(name)} if terminate
 
       # sort and concatenate committees
       committees = committees.sort_by {|name, chair| name.downcase}.
-	map {|name, chair| "    #{name.ljust(23)} #{chair}"}.
-	join("\n")
+        map {|name, chair| "    #{name.ljust(23)} #{chair}"}.
+        join("\n")
 
       # replace committee info in the section, and then replace the
       # section in the committee-info contents
@@ -198,8 +196,8 @@ module ASF
 
       # build new section
       section  = ["#{pmc}  (est. #{date.strftime('%m/%Y')})"]
-      people.sort.each do |id, name|
-        name = "#{name.ljust(26)} <#{...@apache.org>"
+      people.sort.each do |id, person|
+        name = "#{person[:name].ljust(26)} <#{...@apache.org>"
         section << "    #{(name).ljust(59)} [#{date.strftime('%Y-%m-%d')}]"
       end
 
diff --git a/www/board/agenda/views/actions/todos.json.rb b/www/board/agenda/views/actions/todos.json.rb
index 760001d..29b6bb6 100644
--- a/www/board/agenda/views/actions/todos.json.rb
+++ b/www/board/agenda/views/actions/todos.json.rb
@@ -7,9 +7,6 @@ TLPREQ = '/srv/secretary/tlpreq'
 date = params[:date].gsub('-', '_')
 date.untaint if date =~ /^\d+_\d+_\d+$/
 agenda = "board_agenda_#{date}.txt"
-`svn up #{TLPREQ}`
-victims = Dir["#{TLPREQ}/victims-#{date}.*.txt"].
-  map {|name| File.read(name.untaint).lines().map(&:chomp)}.flatten
 
 # fetch minutes
 @minutes = agenda.sub('_agenda_', '_minutes_')
@@ -25,10 +22,12 @@ end
 minutes[:todos] ||= {}
 todos = minutes[:todos].dup
 
+parsed_agenda = Agenda.parse(agenda, :full)
+
 # iterate over the agenda, finding items where there is either comments or
 # minutes that can be forwarded to the PMC
 feedback = []
-Agenda.parse(agenda, :full).each do |item|
+parsed_agenda.each do |item|
   # select exec officer, additional officer, and committee reports
   next unless item[:attach] =~ /^(4[A-Z]|\d|[A-Z]+)$/
   next unless item['chair_email']
@@ -48,8 +47,7 @@ end
 if @remove and env.password
   chairs = ASF::Service.find('pmc-chairs')
 
-  people = @remove.select {|id, checked| checked}.
-    map {|id, checked| ASF::Person.find(id)}
+  people = @remove.map {|id| ASF::Person.find(id)}
 
   ASF::LDAP.bind(env.user, env.password) do
     chairs.remove people
@@ -59,67 +57,64 @@ if @remove and env.password
   minutes[:todos][:removed] += people.map {|person| person.id}
 end
 
-if @add and env.password
-  chairs = ASF::Service.find('pmc-chairs')
-
-  people = @add.select {|id, checked| checked}.
-    map {|id, checked| ASF::Person.find(id)}
+# update committee-info.txt
+if (@change || @establish || @terminate) and env.password
+  cinfo = "#{ASF::SVN['private/committers/board']}/committee-info.txt"
 
-  ASF::LDAP.bind(env.user, env.password) do
-    chairs.add people
+  todos  = Array(@change) + Array(@establish) + Array(@terminate)
+  if todos.length == 1
+    title = todos.first['title']
+  else
+    title = 'board resolutions: ' + todos.map {|todo| todo['name']}.join(', ')
   end
 
-  # send out congratulations email
-  ASF::Mail.configure
-  sender = ASF::Person.new(env.user)
-  mail = Mail.new do
-    from "#{sender.public_name.inspect} <#{...@apache.org>".untaint
-
-    to people.map do |person|
-      "#{person.public_name.inspect} <#{...@apache.org>".untaint
+  ASF::SVN.update cinfo, title, env, _ do |tmpdir, contents|
+    unless minutes[:todos][:next_month]
+      # update list of reports expected next month
+      missing = parsed_agenda.
+        select {|item| item[:attach] =~ /^[A-Z]+$/ and item['missing']}.
+        map {|item| item['title']}
+      contents = ASF::Committee.update_next_month(contents, 
+        Date.parse(date.gsub('_', '-')), missing, 
+        Array(@establish).map {|resolution| resolution['name']})
     end
 
-    cc 'Apache Board <bo...@apache.org>'
+    # update chairs from establish, change, and terminate resolutions
+    chairs = todos.
+      map {|resolution| [resolution['name'], resolution['chair']]}.to_h
+    contents = ASF::Committee.update_chairs(contents, chairs, @terminate)
 
-    subject "Congratulations on your new role at Apache"
+    # add people from establish resolutions
+    established = Date.parse(date.gsub('_', '-'))
+    Array(@establish).each do |resolution|
+      item = parsed_agenda.find do |item| 
+        item['title'] == resolution['title']
+      end
 
-    body "Dear new PMC chairs,\n\nCongratulations on your new role at " +
-    "Apache. I've changed your LDAP privileges to reflect your new " +
-    "status.\n\nPlease read this and update the foundation records:\n" +
-    "https://svn.apache.org/repos/private/foundation/officers/advice-for-new-pmc-chairs.txt" +
-    "\n\nWarm regards,\n\n#{sender.public_name}"
-  end
+      contents = ASF::Committee.establish(contents, resolution['name'], 
+        established, item['people'])
+    end
 
-  mail.deliver!
+    contents
+  end
 
-  minutes[:todos][:added] ||= []
-  minutes[:todos][:added] += people.map {|person| person.id}
+  minutes[:todos][:next_month] = true
+  File.write minutes_file, YAML.dump(minutes)
 end
 
+# update LDAP, create victims.txt
 if @establish and env.password
-  establish = @establish.select {|title, checked| checked}.map(&:first)
-
-  # common to all establish resolutions
-  chairs = ASF::Service.find('pmc-chairs')
-  cinfo = "#{ASF::SVN['private/committers/board']}/committee-info.txt"
-  established = Date.parse(date.gsub('_', '-'))
+  @establish.each do |resolution|
+    pmc = resolution['name']
 
-  # update LDAP, committee-info.txt
-  establish.each do |pmc|
-    resolution = Agenda.parse(agenda, :full).find do |item| 
-      item['title'] == "Establish #{pmc}"
+    item = parsed_agenda.find do |item| 
+      item['title'] == resolution['title']
     end
 
-    chair = ASF::Person.find(resolution['chair'])
-    members = resolution['people'].map {|id, hash| ASF::Person.find(id)}
-    people = resolution['people'].map {|id, hash| [id, hash[:name]]}
-
-    ASF::SVN.update cinfo, resolution['title'], env, _ do |tmpdir, contents|
-      ASF::Committee.establish(contents, pmc, established, people)
-    end
+    members = item['people'].map {|id, hash| ASF::Person.find(id)}
+    people = item['people'].map {|id, hash| [id, hash[:name]]}
 
     ASF::LDAP.bind(env.user, env.password) do
-      chairs.add [chair] unless chairs.members.include? chair
       guineapig = ASF::Committee::GUINEAPIGS.include?(pmc.downcase)
 
       # old style definitions
@@ -136,7 +131,11 @@ if @establish and env.password
       # new style definitions
       project = ASF::Project[pmc.downcase]
       if not project
-        project.create(members, members)
+        unless ASF::Committee[pmc.downcase]
+          ASF::Committee.add(pmc.downcase, members)
+        end
+
+        ASF::Project.find(pmc.downcase).create(members, members)
       elsif not guineapig
         # sync project owners with new PMC list
         project.add_owners(members)
@@ -146,19 +145,80 @@ if @establish and env.password
     end 
   end
 
+  establish = @establish.map {|resolution| resolution['name']}
+
   # create 'victims' file for tlpreq tool
-  count = Dir["#{TLPREQ}/victims-#{date}.*.txt"].length
-  message = "record #{date} approved TLP resolutions"
-  ASF::SVN.update TLPREQ, message, env, _ do |tmpdir|
-    filename = "victims-#{date}.#{count}.txt"
-    contents = establish.join("\n") + "\n"
-    File.write "#{tmpdir}/#{filename}", contents
-    _.system "svn add #{tmpdir}/#{filename}"
+  `svn up #{TLPREQ}`
+  establish -= Dir["#{TLPREQ}/victims-#{date}.*.txt"].
+     map {|name| File.read(name.untaint).lines().map(&:chomp)}.flatten
+  unless establish.empty?
+    count = Dir["#{TLPREQ}/victims-#{date}.*.txt"].length
+    message = "record #{date} approved TLP resolutions"
+    ASF::SVN.update TLPREQ, message, env, _ do |tmpdir|
+      filename = "victims-#{date}.#{count}.txt"
+      contents = establish.join("\n") + "\n"
+      File.write "#{tmpdir}/#{filename}", contents
+      _.system "svn add #{tmpdir}/#{filename}"
+    end
+  end
+end
+
+# update LDAP and send out congratulatory email
+if (@change || @establish) and env.password
+  chairs = ASF::Service.find('pmc-chairs')
+
+  todos  = Array(@change) + Array(@establish)
+  people = todos.map {|todo| ASF::Person.find(todo['chair'])}.uniq
+
+  # add new chairs to pmc-chairs
+  unless (people-chairs.members).empty?
+    ASF::LDAP.bind(env.user, env.password) do
+      chairs.add people-chairs.members
+    end
+  end
+
+  # send out congratulations email
+  ASF::Mail.configure
+  sender = ASF::Person.new(env.user)
+  mail = Mail.new do
+    from "#{sender.public_name.inspect} <#{...@apache.org>".untaint
+
+    to people.map {|person|
+      "#{person.public_name.inspect} <#{...@apache.org>".untaint
+    }.to_a
+
+    cc 'Apache Board <bo...@apache.org>'
+
+    subject "Congratulations on your new role at Apache"
+
+    body "Dear new PMC chairs,\n\nCongratulations on your new role at " +
+    "Apache. I've changed your LDAP privileges to reflect your new " +
+    "status.\n\nPlease read this and update the foundation records:\n" +
+    "https://svn.apache.org/repos/private/foundation/officers/advice-for-new-pmc-chairs.txt" +
+    "\n\nWarm regards,\n\n#{sender.public_name}"
   end
-  victims += establish
 
+  mail.deliver!
+end
+
+########################################################################
+#                    Update list of completed todos                    #
+########################################################################
+
+if @change
+  minutes[:todos][:changed] ||= []
+  minutes[:todos][:changed] += @change.map {|resolution| resolution['name']}
+end
+
+if @establish
   minutes[:todos][:established] ||= []
-  minutes[:todos][:established] += establish
+  minutes[:todos][:established] += 
+    @establish.map {|resolution| resolution['name']}
+end
+
+if @terminate
+  minutes[:todos][:terminated] ||= []
+  minutes[:todos][:terminated] += @terminate
 end
 
 unless todos == minutes[:todos]
@@ -174,18 +234,20 @@ establish = []
 terminate = {}
 change = []
 
-Agenda.parse(agenda, :full).each do |item|
+parsed_agenda.each do |item|
   next unless item[:attach] =~ /^7\w$/
   if item['title'] =~ /^Change (.*?) Chair$/ and item['people']
+    next if Array(minutes[:todos][:changed]).include? $1
     change << {name: $1, resolution: item['title'], chair: item['chair']}
     item['people'].keys.each do |person|
       transitioning[ASF::Person.find(person)] = item['title']
     end
   elsif item['title'] =~ /^Establish\s*(.*?)\s*$/ and item['chair']
-    next if victims.include? $1
+    next if Array(minutes[:todos][:established]).include? $1
     establish << {name: $1, resolution: item['title'], chair: item['chair']}
     transitioning[ASF::Person.find(item['chair'])] = item['title']
   elsif item['title'] =~ /^Terminate\s*(.*?)\s*$/
+    next if Array(minutes[:todos][:terminated]).include? $1
     terminate[$1] = item['title']
   end
 end
diff --git a/www/board/agenda/views/pages/adjournment.js.rb b/www/board/agenda/views/pages/adjournment.js.rb
index 10cbf40..5677cde 100644
--- a/www/board/agenda/views/pages/adjournment.js.rb
+++ b/www/board/agenda/views/pages/adjournment.js.rb
@@ -67,7 +67,7 @@ class Adjournment < Vue
         end
 
         unless Todos.remove.empty?
-          _TodoActions action: 'remove'
+          _TodoRemove
         end
 
         unless Todos.feedback.empty?
@@ -150,15 +150,15 @@ class PMCActions < Vue
 
     _ul.checklist @resolutions do |item|
       _li do
-	_input type: 'checkbox', checked: item.checked,
-	  onChange:-> { item.checked = !item.checked; self.refresh() }
+        _input type: 'checkbox', checked: item.checked,
+          onChange:-> { item.checked = !item.checked; self.refresh() }
 
-	_Link text: item.title, href: Todos.link(item.title)
+        _Link text: item.title, href: Todos.link(item.title)
 
-	if item.minutes
-	  _ ' - '
-	  _Link text: item.minutes, href: Todos.link(item.title)
-	end
+        if item.minutes
+          _ ' - '
+          _Link text: item.minutes, href: Todos.link(item.title)
+        end
       end
     end
 
@@ -166,28 +166,33 @@ class PMCActions < Vue
       onClick: self.submit
   end
 
-  # update check marks based on current Todo list
+  # gather a list of resolutions
   def created()
     @resolutions = []
+
     Agenda.index.each do |item|
-      if Todos.change.any? {|todo| todo.resolution == item.title}
-        action = :change
-      elsif Todos.establish.any? {|todo| todo.resolution == item.title}
-        action = :establish
-      elsif Todos.terminate.any? {|todo| todo.resolution == item.title}
-        action = :terminate
-      else
-        next
-      end
-    
-      minutes = Minutes.get(item.title)
+      action = name = nil
+
+      %w(change establish terminate).each do |todo_type|
+        Todos[todo_type].each do |todo| 
+          if todo.resolution == item.title
+            minutes = Minutes.get(item.title)
  
-      @resolutions << {
-        action: action,
-        title: item.title,
-        minutes: minutes,
-        checked: (minutes != 'tabled')
-      }
+            resolution = {
+              action: todo_type,
+              name: todo.name,
+              title: item.title,
+              minutes: minutes,
+              checked: (minutes != 'tabled')
+            }
+
+            resolution.chair = todo.chair if todo.chair
+            resolution.people = todo.people if todo.people
+
+            @resolutions << resolution
+          end
+        end
+      end
     end
 
     self.refresh()
@@ -196,13 +201,35 @@ class PMCActions < Vue
   def refresh()
     @disabled = @resolutions.all? {|item| not item.checked}
   end
+
+  def submit()
+    data = {
+      change: [],
+      establish: [],
+      terminate: []
+    }
+
+    @resolutions.each do |resolution|
+      data[resolution.action] << resolution if resolution.checked
+    end
+
+    data.change = nil if data.change.empty?
+    data.establish = nil if data.establish.empty?
+    data.terminate = nil if data.terminate.empty?
+
+    @disabled = true
+    post "secretary-todos/#{Agenda.title}", data do |todos|
+      @disabled = false
+      Todos.set todos
+    end
+  end
 end
 
 ########################################################################
-#                          Add, Remove chairs                          #
+#                            Remove chairs                             #
 ########################################################################
 
-class TodoActions < Vue
+class TodoRemove < Vue
   def initialize
     @checked = {}
     @disabled = true
@@ -211,7 +238,7 @@ class TodoActions < Vue
 
   # update check marks based on current Todo list
   def created()
-    @people = Todos[@@action]
+    @people = Todos.remove
 
     # uncheck people who were removed
     for id in @checked
@@ -244,11 +271,7 @@ class TodoActions < Vue
   end
 
   def render
-    if @@action == 'add'
-      _p 'Add to pmc-chairs and email welcome message:'
-    else
-      _p 'Remove from pmc-chairs:'
-    end
+    _p 'Remove from pmc-chairs:'
 
     _ul.checklist @people do |person|
       _li do
@@ -261,14 +284,6 @@ class TodoActions < Vue
         _a person.id,
           href: "/roster/committer/#{person.id}"
         _ " (#{person.name})"
-
-        if @@action == 'add' and person.resolution
-          resolution = Minutes.get(person.resolution)
-          if resolution
-            _ ' - '
-            _Link text: resolution, href: Todos.link(person.resolution)
-          end
-        end
       end
     end
 
@@ -279,10 +294,12 @@ class TodoActions < Vue
   def submit()
     @disabled = true
 
-    data = {}
-    data[@@action] = @checked
+    remove = []
+    for id in @checked
+      remove << id if @checked[id]
+    end
 
-    post "secretary-todos/#{Agenda.title}", data do |todos|
+    post "secretary-todos/#{Agenda.title}", remove: remove do |todos|
       @disabled = false
       Todos.set todos
     end

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" <co...@whimsical.apache.org>'].