On Nov 4, 2017 3:34 PM, <ru...@apache.org> wrote:

> 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 df26a69  initial import from svn:foundation/board/scripts/
> committers-report.rb
> df26a69 is described below
>
> commit df26a69cbad10dbc5fdea7436a2ee816ffe00e26
> Author: Sam Ruby <ru...@intertwingly.net>
> AuthorDate: Sat Nov 4 15:33:18 2017 -0400
>
>     initial import from svn:foundation/board/scripts/committers-report.rb
>
>     replace ARGV with ASF::SVN
>     remove puts
> ---
>  lib/whimsy/asf/board.rb                          |  10 +-
>  www/board/agenda/Gemfile                         |   2 +
>  www/board/agenda/routes.rb                       |   5 +
>  www/board/agenda/views/committers_report.text.rb | 275
> +++++++++++++++++++++++
>  4 files changed, 291 insertions(+), 1 deletion(-)
>
> diff --git a/lib/whimsy/asf/board.rb b/lib/whimsy/asf/board.rb
> index 6e82d5a..7310220 100644
> --- a/lib/whimsy/asf/board.rb
> +++ b/lib/whimsy/asf/board.rb
> @@ -23,7 +23,15 @@ module ASF
>
>      # time of next meeting
>      def self.nextMeeting
> -      self.calendar.select {|time| time > Time.now.utc}.min
> +      time = self.calendar.select {|time| time > Time.now.utc}.min
> +
> +      if not time
> +        require 'chronic'
> +        time ||= Chronic.parse('3rd wednesday this month')
> +        time = Chronic.parse('3rd wednesday next month') if time <
> Time.now.utc
> +      end
> +
> +      time
>      end
>
>      # list of PMCs reporting in the specified meeting
> diff --git a/www/board/agenda/Gemfile b/www/board/agenda/Gemfile
> index 918fc49..97fea07 100644
> --- a/www/board/agenda/Gemfile
> +++ b/www/board/agenda/Gemfile
> @@ -30,6 +30,8 @@ gem 'mime-types', '~> 2.6'
>
>  gem 'rubyXL'
>
> +gem 'chronic'
> +
>  group :test do
>    gem 'rspec'
>    gem 'puma'
> diff --git a/www/board/agenda/routes.rb b/www/board/agenda/routes.rb
> index 5fc58f7..c56b267 100755
> --- a/www/board/agenda/routes.rb
> +++ b/www/board/agenda/routes.rb
> @@ -269,6 +269,11 @@ get %r{/(\d\d\d\d-\d\d-\d\d).json} do |file|
>    end
>  end
>
> +# draft committers report
> +get '/text/committers-report' do
> +  _text :committers_report
> +end
> +
>  # draft minutes
>  get '/text/minutes/:file' do |file|
>    file = "board_minutes_#{file.gsub('-','_')}.txt".untaint
> diff --git a/www/board/agenda/views/committers_report.text.rb
> b/www/board/agenda/views/committers_report.text.rb
> new file mode 100644
> index 0000000..25c28c9
> --- /dev/null
> +++ b/www/board/agenda/views/committers_report.text.rb
> @@ -0,0 +1,275 @@
> +require 'chronic'
> +
> +## This is a script to generate an email for committ...@apache.org from
> +## an agenda file. It also requires the calendar.txt so it can determine
> +## the next meeting's date and committee-info.txt so it can determine
> +## who the VP is for a project.
> +
> +# Add the right prefix to a number
> +def prefixNumber(number)
> +  if number % 10 == 1
> +    return number + "st"
> +  end
> +  if number % 10 == 2
> +    return number + "nd"
> +  end
> +  return number + "th"
> +end
> +
> +board_svn = ASF::SVN['private/foundation/board']
> +agenda_file = Dir["#{board_svn}/board_agenda_*.txt"].last.untaint
> +
> +##### Parse the agenda to find the data items above
> +
> +# Data items from agenda
> +date            = nil
> +day             = nil
> +daynum          = nil
> +month           = nil
> +year            = nil
> +directors       = Array.new
> +officers        = Array.new
> +guests          = Array.new
> +minutes         = Array.new
> +resolutions     = Array.new
> +missing_reports = Array.new
> +
> +# State variables
> +parsing_directors   = false
> +parsing_officers    = false
> +parsing_guests      = false
> +parsing_resolutions = false
> +parsing_attachment  = nil
> +current_attachment  = nil
> +
> +File.open(agenda_file).each do |line|
> +
> +  # 1: Find the date, this is used in the title and various other places
> +  if !date && line =~ /(\w*) (\d\d?), (\d{4})$/
> +    month = $1
> +    daynum = $2
> +    day = prefixNumber(daynum)
> +    year = $3
> +    date = line.strip()
> +    next
> +  end
> +
> +  # 2: Get the list of expected directors
> +  if line.strip == "Directors (expected to be) Present:"
> +    parsing_directors = true
> +    next
> +  end
> +  if parsing_directors
> +    if line.strip == "Directors (expected to be) Absent:"
> +      parsing_directors = false
> +      next
> +    end
> +    if line.strip == ""
> +      next
> +    end
> +    directors << line.strip
> +    next
> +  end
> +
> +  if line.strip == "Executive Officers (expected to be) Present:"
> +    parsing_officers = true
> +    next
> +  end
> +  if parsing_officers
> +    if line.strip == "Executive Officers (expected to be) Absent:"
> +      parsing_officers = false
> +      next
> +    end
> +    if line.strip == ""
> +      next
> +    end
> +    officers << line.strip
> +    next
> +  end
> +
> +  # 3: Get the list of expected guests
> +  # TODO: Same as directors code above, consider a function
> +  if line.strip == "Guests (expected):"
> +    parsing_guests = true
> +    next
> +  end
> +  if parsing_guests
> +    if line =~ /\d. Minutes from previous meetings/
> +      parsing_guests = false
> +      next
> +    end
> +    if line.strip == ""
> +      next
> +    end
> +    guests << line.strip
> +    next
> +  end
> +
> +  # 4: Get the list of listed minutes
> +  if line =~ /[A-Z]\. The meeting of (\w*) \d\d?, \d{4}$/
> +    minutes << $1
> +    next
> +  end
> +
> +  # 5: Get the list of resolutions
> +  if line =~ /\d. Special Orders/
> +    parsing_resolutions = true
> +    next
> +  end
> +  if parsing_resolutions
> +    if line =~ /\d. Discussion Items/
> +      parsing_resolutions = false
> +      next
> +    end
> +    if line =~ /^\s*[A-Z]\. /
> +      resolutions << line.strip
> +      next
> +    end
> +  end
> +
> +  # 6: Get the list of missing reports (aka empty attachments)
> +  if !parsing_attachment && line =~ /^Attachment (..?): (.*)/
> +    parsing_attachment = $1
> +    current_attachment = $2
> +    next
> +  end
> +  if parsing_attachment
> +    if line.strip == ""
> +      next
> +    end
> +    if line.strip == "-----------------------------------------"
> +      if parsing_attachment.to_i.between?(1, 6)
> +        puts "Skipping missing President Committee attachment:
> #{current_attachment}"
> +      else
> +        missing_reports << current_attachment
> +      end
> +      parsing_attachment = nil
> +      next
> +    end
> +    parsing_attachment = nil
> +    next
> +  end
> +
> +end
> +
> +##### 7: Find out the date of the next board report
> +
> +calendar_file  = ASF::SVN['private/committers/board'] + "/calendar.txt"
> +found_date = false
> +next_meeting = nil
> +File.open(calendar_file).each do |line|
> +    if line =~ /\$Date:/
> +      next
> +    end
> +    if line =~ /#{month} #{year}/
> +      found_date = true
> +      next
> +    end
> +    if found_date
> +      if line =~ /(\d+) (\w+) \d{4}/
> +        next_meeting = prefixNumber($1) + " of " + $2
> +        break
> +      end
> +    end
> +end
> +if !next_meeting
> +  puts "Error: Unable to determine the next meeting from
> #{calendar_file}\n"
> +  nxt = Chronic.parse('3rd wednesday next month').to_s
> +  ## Returns something like: Wed Dec 21 12:00:00 -0500 2011
> +  if nxt =~ /Wed (\w{3}) (\d\d).*(\d{4})$/
> +    next_meeting = "#{$1} #{$2} #{$3}"
> +  end
> +  ##exit 1
> +end
> +if !next_meeting
> +  puts "Error: Unable to determine the next meeting at all\n"
> +  exit 1
> +end
> +
> +##### 8: Find names of the VPs of TLPs in resolutions
> +
> +## this does not work, since new TLPs are not yet in committee-info.txt
> +## instead we should parse this from the resolution
> +
> +committee_file = ASF::SVN['private/committers/board'] +
> "/committee-info.txt"
> +parsing_projects = false
> +resolution_to_chair = Hash.new
> +File.open(committee_file).each do |line|
> +  if line =~ /\d. APACHE SOFTWARE FOUNDATION COMMITTEES/
> +    parsing_projects = true
> +  end
> +  if parsing_projects
> +    if line =~ /^\s+([\w\s]+)\s\s+([^<]*)<[^>]*>\s*$/
> +      project = $1
> +      chair = $2
> +      project = project.strip
> +      resolutions.each() do |resolution|
> +        if resolution =~ /#{project}/
> +          resolution_to_chair[resolution] = chair.strip
> +        end
> +      end
> +    end
> +    if line =~ /={76}/
> +      parsing_projects = false
> +      break
> +    end
> +  end
> +end
> +
> +##### Prepare the arrays for output
> +t_directors = directors.join(", ")
> +t_officers = officers.join(", ")
> +t_guests = guests.join(", ")
> +if !minutes.empty?
> +  t_minutes = "\nThe " + minutes.join(", ").sub(/, ([^,]*)$/, ' and \1')
> + " minutes were " + (minutes.length > 1 ? "all " : "") + "approved.
> \nMinutes will be posted to http://www.apache.org/
> foundation/records/minutes/\n"
> +else
> +  t_minutes = ""
> +end
> +if !missing_reports.empty?
> +  t_missing_reports = "The following reports were not received and are
> expected next month: \n\n  "
> +  t_missing_reports += missing_reports.join("\n  ")
> +  t_missing_reports += "\n"
> +else
> +  t_missing_reports = ""
> +end
> +if !resolutions.empty?
> +  t_resolutions = "The following resolutions were passed unanimously:
> \n\n"
> +  resolutions.each() do |resolution|
> +    t_resolutions += "  #{resolution}";
> +    # if(resolution_to_chair[resolution])
> +    #   t_resolutions += " (" + resolution_to_chair[resolution] +", VP)"
> +    # end
> +    t_resolutions += " (???, VP)\n"
> +  end
> +else
> +  t_resolutions = ""
> +end
> +
> +##### Write the report
> +report = <<REPORT
> +PLEASE EDIT THIS, IT IS ONLY AN ESTIMATE.
> +From: chair...@apache.org
> +To: committ...@apache.org
> +Reply-To: bo...@apache.org
> +Subject: ASF Board Meeting Summary - #{month} #{daynum}, #{year}
> +
> +The #{month} board meeting took place on the #{day}.
> +
> +The following directors were present:
> +
> +  #{t_directors}
> +
> +The following officers were present:
> +
> +  #{t_officers}
> +
> +The following guests were present:
> +
> +  #{t_guests}
> +#{t_minutes}
> +All of the received reports to the board were approved.
> +
> +#{t_missing_reports}
> +#{t_resolutions}
> +The next board meeting will be on the #{next_meeting}.
> +REPORT
>
> --
> To stop receiving notification emails like this one, please contact
> ['"comm...@whimsical.apache.org" <comm...@whimsical.apache.org>'].
>

Reply via email to