class ASF::Committee

Representation for a committee (either a PMC, a board committee, or a President’s committee). This data is parsed from committee-info.txt|.yaml, and is augmened by data from LDAP, and ASF::Mail.

Note that the simple attributes which are sourced from committee-info.txt data is generally not available until ASF::Committee.load_committee_info is called.

Similarly, the simple attributes which are sourced from LDAP is generally not available until ASF::Project.preload is called.

representation of Committee, i.e. entry in committee-info.txt includes PMCs and other committees, but does not include podlings

Constants

NAMEADDRLEN
NAMELEN

Original field sizes for PMC section

Attributes

chairs[RW]

list of chairs for this committee. Returned as a list of hashes containing the :name and :id. Data is obtained from committee-info.txt.

established[RW]

Date this committee was established in the format MM/YYYY. Data is obtained from committee-info.txt.

info[R]

list of members for this committee. Returned as a list of ids. Data is obtained from committee-info.txt.

paragraph[RW]

type of non-pmc entry (from its paragraph heading in committee-info.txt)

report[W]

when this committee is next expected to report. May be a string containing values such as “Next month: missing in May”, “Next month: new, monthly through July”. Data is obtained from committee-info.txt.

roster[RW]

list of members for this committee. Returned as a list of hash mapping ids to a hash of :name and :date values. Data is obtained from committee-info.txt.

schedule[RW]

list of months when this committee typically reports. Returned as a comma separated string. Data is obtained from committee-info.txt.

Public Class Methods

[](name) click to toggle source

return committee only if it actually exists

Calls superclass method ASF::Base::[]
# File lib/whimsy/asf/ldap.rb, line 1348
def self.[](name)
  committee = super
  # Cannot rely on presence/absence of LDAP record as projects includes podlings
  (ASF::Committee.pmcs + ASF::Committee.nonpmcs).map(&:name).include?(name) ? committee : nil
end
appendtlpmetadata(input, committee, description, date_established) click to toggle source

append the description for a new tlp committee. this is intended to be called from todos.json.rb in the block for ASF::SVN.update

# File lib/whimsy/asf/committee.rb, line 720
def self.appendtlpmetadata(input, committee, description, date_established)
  YamlFile.replace_section(input, :tlps) do |section, yaml|
    output = section # default no change
    if yaml[:cttees][committee] && !yaml[:cttees][committee][:retired]
      Wunderbar.warn "Entry for '#{committee}' already exists under :cttees"
    elsif yaml[:tlps][committee] && !yaml[:tlps][committee][:retired]
      Wunderbar.warn "Entry for '#{committee}' already exists under :tlps"
    else
      if section[committee] # already exists; must be retired
        diary = section[committee][:diary]
        if !diary
            diary = section[committee][:diary] = []
            diary << {established: section[committee][:established]}
        end
        diary << {retired: section[committee].delete(:retired)}
        diary << {resumed: date_established.strftime('%Y-%m')}
      else
        section[committee] = {
            site: "http://#{committee}.apache.org",
            description: description,
            established: date_established.strftime('%Y-%m'),
        }
      end
      output = section.sort.to_h
    end
    output
  end
end
establish(contents, pmc, date, people) click to toggle source

insert (replacing if necessary) a new committee into committee-info.txt

# File lib/whimsy/asf/committee.rb, line 357
def self.establish(contents, pmc, date, people)
  ########################################################################
  #         insert into assigned quarterly reporting periods             #
  ########################################################################

  # split into blocks
  blocks = contents.split("\n\n")

  # find the reporting schedules
  index =  blocks.find_index {|section| section =~ /January/}

  # extract reporting schedules
  slots = [
    blocks[index + 0].split("\n"),
    blocks[index + 1].split("\n"),
    blocks[index + 2].split("\n"),
  ]

  unless slots.any? {|slot| slot.include? "    " + pmc}
    # ensure that spacing is uniform
    slots.each {|slot| slot.unshift '' unless slot[0] == ''}

    # determine tie breakers between months of the same length
    preference = [(date.month) % 3, (date.month - 1) % 3, (date.month - 2) % 3]

    # pick the month with the shortest list
    slot = (0..2).map {|i| [slots[i].length, preference, i]}.min.last

    # temporarily remove headers
    headers = slots[slot].shift(3)

    # insert pmc into the reporting schedule
    slots[slot] << "    " + pmc

    # sort entries, case insensitive
    slots[slot].sort_by!(&:downcase)

    # restore headers
    slots[slot].unshift(*headers) # () are required here to prevent warning

    # re-insert reporting schedules
    blocks[index + 0] = slots[0].join("\n")
    blocks[index + 1] = slots[1].join("\n")
    blocks[index + 2] = slots[2].join("\n")

    # re-attach blocks
    contents = blocks.join("\n\n")
  end

  ########################################################################
  #         insert into COMMITTEE MEMBERSHIP AND CHANGE PROCESS          #
  ########################################################################

  # split into foot, sections (array) and head
  foot = contents[/^=+\s*\Z/]
  contents.sub! %r{^=+\s*\Z}, ''
  sections = contents.split(/^\* /)
  head = sections.shift

  # remove existing section (if present)
  sections.delete_if {|section| section.downcase.start_with? pmc.downcase}

  # build new section
  entries = people.map do |id, person|
    [person[:name], "<#{id}@apache.org>", "[#{date.strftime('%Y-%m-%d')}]"]
  end
  people = format_pmc(entries)

  section = ["#{pmc}  (est. #{date.strftime('%m/%Y')})"] + people.sort

  # add new section
  sections << section.join("\n") + "\n\n\n"

  # sort sections
  sections.sort_by!(&:downcase)

  # re-attach parts
  head + '* ' + sections.join('* ') + foot
end
find(name, clear=false) click to toggle source

Finds a committee based on the name of the Committee. Is aware of a number of aliases for a given committee. Will set display name if the name being searched on contains an uppercase character. If clear is true, then remove any cached entry

Calls superclass method ASF::Base::find
# File lib/whimsy/asf/committee.rb, line 607
def self.find(name, clear=false)
  raise ArgumentError.new('name: must not be nil') unless name
  namelc = @@namemap.call(name.downcase)
  collection[namelc] = nil if clear
  result = super(namelc)
  result.display_name = name if name =~ /[A-Z]/
  result
end
format_pmc(people, namelen=NAMELEN, nameaddrlen=NAMEADDRLEN) click to toggle source

format a PMC entry people: array of entries in the form [name, email, date+comment] namelen: default size to allow for name field nameaddrlen: default size to allow for name + email field fields will be separated by at least one space on output The defaults are taken from the originals to avoid needless change

# File lib/whimsy/asf/committee.rb, line 443
def self.format_pmc(people, namelen=NAMELEN, nameaddrlen=NAMEADDRLEN)
  maillen = 0
  people.each do |name, email, _datefield|
    namelen = [namelen, name.size].max
    maillen = [maillen, email.size].max
  end
  # +1 for space between fields
  nameaddrlen = [nameaddrlen, namelen + maillen + 1].max
  people.map do |name, email, datefield|
    nameaddr = "#{name.ljust(namelen)} #{email}"
    "    #{(nameaddr).ljust(nameaddrlen)} #{datefield}"
  end
end
load_committee_info(contents = nil, info = nil) click to toggle source

load committee info from committee-info.txt. Will not reparse if the file has already been parsed and the underlying file has not changed. the parameters are currently only used by www/board/agenda/routes.rb

# File lib/whimsy/asf/committee.rb, line 112
def self.load_committee_info(contents = nil, info = nil)
  if contents
    if info
      @committee_mtime = @@svn_change =
        Time.parse(info[/Last Changed Date: (.*) \(/, 1]).gmtime
    else
      @committee_mtime = @@svn_change = Time.now
    end

    @nonpmcs, @officers, @committee_info = parse_committee_info_nocache(contents)
  else
    board = ASF::SVN.find('board')
    return unless board
    file = File.join(board, 'committee-info.txt')
    return unless File.exist? file

    if @committee_mtime and File.mtime(file) <= @committee_mtime
      return @committee_info if @committee_info
    end

    @committee_mtime = File.mtime(file)
    @@svn_change = Time.parse(ASF::SVN.getInfoItem(file, 'last-changed-date')).gmtime

    @nonpmcs, @officers, @committee_info = parse_committee_info_nocache(File.read(file))
  end
  @committee_info
end
load_committee_metadata() click to toggle source

load committee metadata from committee-info.yaml. Will not reparse if the file has already been parsed and the underlying file has not changed.

# File lib/whimsy/asf/committee.rb, line 683
def self.load_committee_metadata
  board = ASF::SVN.find('board')
  return unless board
  file = File.join(board, 'committee-info.yaml')
  return unless File.exist? file

  return @committee_metadata if @committee_metadata and @committee_metadata_mtime and File.mtime(file) <= @committee_metadata_mtime

  @committee_metadata_mtime = File.mtime(file)
  @committee_metadata = YAML.load_file file
end
meta_change() click to toggle source

get the changed date for the meta data

# File lib/whimsy/asf/committee.rb, line 696
def self.meta_change
  @committee_metadata_mtime
end
metadata(committee) click to toggle source

get the metadata for a given committee.

# File lib/whimsy/asf/committee.rb, line 701
def self.metadata(committee)
  committee = committee.name if committee.is_a? ASF::Committee
  load_committee_metadata[:tlps][committee] || load_committee_metadata[:cttees][committee]
end
new(*args) click to toggle source

create an empty committee instance

Calls superclass method ASF::Base::new
# File lib/whimsy/asf/committee.rb, line 57
def initialize(*args)
  @info = []
  @chairs = []
  @roster = {}
  super
end
nonpmcs() click to toggle source

return a list of non-PMC committees. Data is obtained from committee-info.txt

# File lib/whimsy/asf/committee.rb, line 583
def self.nonpmcs
  ASF::Committee.load_committee_info # ensure data exists
  @nonpmcs
end
officer(role) click to toggle source

look up an individual officer

# File lib/whimsy/asf/committee.rb, line 598
def self.officer(role)
  office = self.officers.find {|officer| officer.name == role}
  office && ASF::Person.find(office.chairs.first[:id])
end
officers() click to toggle source

return a list of officers. Data is obtained from committee-info.txt. Note that these entries are returned as instances of ASF::Committee with display_name being the name of the office, and chairs being the individuals who hold that office.

# File lib/whimsy/asf/committee.rb, line 592
def self.officers
  ASF::Committee.load_committee_info # ensure data exists
  @officers
end
parse_committee_info_nocache(contents) click to toggle source

extract chairs, list of nonpmcs, roster, start date, and reporting information from committee-info.txt. @return nonpmcs, officers, committees (including nonpmcs) This can safely be called with any input as it is idempotent For general use, use ASF::Committee.load_committee_info which caches the data

# File lib/whimsy/asf/committee.rb, line 463
def self.parse_committee_info_nocache(contents)
  # List uses full (display) names as keys, but the entries use the canonical names
  # - the local version of find() converts the name
  # - and stores the original as the display name if it has some upper case
  list = Hash.new {|hash, name| hash[name] = find(name, true)}

  # Split the file on lines starting "* ", i.e. the start of each group in section 3
  info = contents.split(/^\* /)
  # Extract the text before first entry in section 3 and split on section headers,
  # keeping sections 1 (COMMITTEES) and 2 (REPORTING).
  head, report = info.shift.split(/^\d\./)[1..2]
  # Drop lines which could match group headers
  head.gsub! %r{^\s+NAME\s+CHAIR\s*$}, ''
  head.gsub! %r{^\s+Office\s+Officer\s*$}i, ''

  # extract the committee chairs (e-mail address is required here)
  # Note: this includes the non-PMC entries

  # Scan for entries even if there is a missing extra space before the chair column
  head.scan(/^[ \t]+\w.*?[ \t]+.*[ \t]+<.*?@apache\.org>/).each do |line|
    # Now weed out the malformed lines
    m = line.match(/^[ \t]+(\w.*?)[ \t][ \t]+(.*)[ \t]+<(.*?)@apache\.org>/)
    if m
      committee, name, id = m.captures
      unless list[committee].chairs.any? {|chair| chair[:id] == id}
        list[committee].chairs << {name: name, id: id}
      end
    else
      # not possible to determine where one name starts and the other begins
      Wunderbar.warn "Missing separator before chair name in: '#{line}'"
    end
  end
  # Extract the non-PMC committees (e-mail address may be absent)
  # first drop leading text (and Officers) so we only match non-PMCs
  nonpmcs = head.sub(/.*?also has /m, '').sub(/ Officers:.*/m, '').
    scan(/^[ \t]+(\w.*?)(?:[ \t][ \t]|[ \t]?$)/).flatten.uniq.
    map {|name| list[name]}

  # Extract officers
  # first drop leading text so we only match officers at end of section
  officers = head.sub(/.*?also has .*? Officers/m, '').
    scan(/^[ \t]+(\w.*?)(?:[ \t][ \t]|[ \t]?$)/).flatten.uniq.
    map {|name| list[name]}

  # store the paragraph identifiers: Board Committees etc
  head_parts = head.split(/^The ASF also has the following +/)
  (1..head_parts.size - 1).each do |h| # skip the first section
    part = head_parts[h]
    type = part[/^([^:]+)/, 1] # capture remains of line excluding colon
    part.scan(/^[ \t]+(\w.*?)(?:[ \t][ \t]|[ \t]?$)/).flatten.uniq.each do |cttee|
      list[cttee].paragraph = type
    end
  end

  # for each committee in section 3
  info.each do |roster|
    # extract the committee name (and parenthesised comment if any)
    name = roster[/(\w.*?)[ \t]+\(est/, 1]
    unless list.include?(name)
      Wunderbar.warn "No chair entry detected for #{name} in section 3"
    end
    committee = list[name]

    # get and normalize the start date
    established = roster[/\(est\. (.*?)\)/, 1]
    established = "0#{established}" if established =~ /^\d\//
    committee.established = established

    # match non-empty entries and check the syntax
    roster.scan(/^[ \t]+.+$/) do |line|
      Wunderbar.warn "Invalid syntax: #{committee.name} '#{line}'" unless line =~ /\s<(.*?)@apache\.org>\s/
    end

    # extract the availids (is this used?)
    committee.info = roster.scan(/<(.*?)@apache\.org>/).flatten

    # drop (chair) markers and extract 0: name, 1: availid, 2: [date], 3: date
    # the date is optional (e.g. infrastructure)
    committee.roster = Hash[roster.gsub(/\(\w+\)/, '').
      scan(/^[ \t]*(.*?)[ \t]*<(.*?)@apache\.org>(?:[ \t]+(\[(.*?)\]))?/).
      map {|l| [l[1], {name: l[0], date: l[3]}]}]
  end

  # process report section
  report.scan(/^([^\n]+)\n---+\n(.*?)\n\n/m).each do |period, committees|
    committees.scan(/^   [ \t]*(.*)/).each do |committee|
      committee, comment = committee.first.split(/[ \t]+#[ \t]+/, 2)
      unless list.include? committee
        Wunderbar.warn "Unexpected name '#{committee}' in report section; ignored"
        next
      end
      committee = list[committee]
      if comment
        committee.report = "#{period}: #{comment}"
      elsif period == 'Next month'
        committee.report = 'Every month'
      else
        committee.schedule = period
      end
    end
  end
  committee_info = (list.values - officers).uniq
  # Check if there are duplicates.
  committee_info.each do |c|
    if c.chairs.length != 1 && c.name != 'fundraising' # hack to avoid reporting non-PMC entry
      Wunderbar.warn "Unexpected chair count for #{c.display_name}: #{c.chairs.inspect rescue ''}"
    end
  end
  return nonpmcs, officers, committee_info
end
pmcs() click to toggle source

return a list of PMC committees. Data is obtained from committee-info.txt

# File lib/whimsy/asf/committee.rb, line 576
def self.pmcs
  committees = ASF::Committee.load_committee_info
  committees - @nonpmcs - @officers
end
record_termination(input, pmc, yyyymm) click to toggle source

record termination date in committee-info.yml Params:

  • input: the contents of committee-info.yml

  • pmc: the pmc name

  • yyyymm: YYYY-MM retirement date

Returns: the updated contents
# File lib/whimsy/asf/committee.rb, line 314
def self.record_termination(input, pmc, yyyymm)
  YamlFile.replace_section(input, :tlps) do |section, _yaml|
    key = ASF::Committee.to_canonical(pmc)
    if section[key]
      section[key][:retired] = yyyymm
      section[key][:name] = pmc
    else
      section[key] = {retired: yyyymm, name: pmc}
    end
    section.sort.to_h
  end
end
svn_change() click to toggle source

Return the Last Changed Date for committee-info.txt in svn as a Time object. Data is based on the previous call to ASF::Committee.load_committee_info.

# File lib/whimsy/asf/committee.rb, line 619
def self.svn_change
  @@svn_change
end
terminate(contents, pmc) click to toggle source

remove committee from committee-info.txt

# File lib/whimsy/asf/committee.rb, line 328
def self.terminate(contents, pmc)
  ########################################################################
  #         remove from assigned quarterly reporting periods             #
  ########################################################################

  # split into blocks
  blocks = contents.split("\n\n")

  # find the reporting schedules
  index =  blocks.find_index {|section| section =~ /January/}

  # remove from each reporting period
  blocks[index + 0].sub! "\n    #{pmc}\n", "\n"
  blocks[index + 1].sub! "\n    #{pmc}\n", "\n"
  blocks[index + 2].sub! "\n    #{pmc}\n", "\n"

  # re-attach blocks
  contents = blocks.join("\n\n")

  ########################################################################
  #         remove from COMMITTEE MEMBERSHIP AND CHANGE PROCESS          #
  ########################################################################

  contents.sub! %r{^\* #{Regexp.escape(pmc)}  ?\(est.*?\n\n+}m, ''

  contents
end
to_canonical(name) click to toggle source

convert committee name to canonical name

# File lib/whimsy/asf/committee.rb, line 104
def self.to_canonical(name)
  @@namemap.call(name.downcase)
end
update_chairs(contents, todos) click to toggle source

update chairs

# File lib/whimsy/asf/committee.rb, line 213
def self.update_chairs(contents, todos)
  # 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 resolutions
  todos.each do |resolution|
    name = resolution['display_name']
    if resolution['action'] == 'terminate'
      committees.delete(name)
    elsif resolution['chair']
      person = ASF::Person.find(resolution['chair'])
      committees[name] = "#{person.public_name} <#{person.id}@apache.org>"
    end
  end

  # sort and concatenate committees
  committees = committees.sort_by { |name, _chair| name.downcase }.
    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
  section[/-\n(.*?)\n\n/m, 1] = committees
  contents[/^1\..*?\n=+/m] = section

  # return result
  contents
end
update_next_month(contents, date, missing, rejected, todos) click to toggle source

update next month section. Remove entries that have reported or or expired; add (or update) entries that are missing; add entries for new committees.

# File lib/whimsy/asf/committee.rb, line 143
def self.update_next_month(contents, date, missing, rejected, todos)
  # extract next month section; and then extract the lines containing
  # '#' signs from within that section
  next_month = contents[/Next month.*?\n\n/m].chomp
  block = next_month[/(.*#.*\n)+/] || ''

  # remove expired entries
  month = date.strftime("%B")
  block.gsub!(/.* # new, monthly through #{month}\n/, '')

  # update/remove existing 'missing' entries
  existing = []
  block.gsub! %r{(.*?)# (missing|not accepted) in .*\n} do |line|
    if missing.include? $1.strip
      existing << $1.strip
      if line.chomp.end_with? month
        line
      elsif line.split(',').last.include? 'not accepted'
        "#{line.chomp}, missing #{month}\n"
      else
        "#{line.chomp}, #{month}\n"
      end
    elsif rejected.include? $1.strip
      existing << $1.strip
      if line.chomp.end_with? month
        line
      else
        "#{line.chomp}, not accepted #{month}\n"
      end
    else
      ''
    end
  end

  # add new 'missing' entries
  (missing - existing).each do |pmc|
    block += "    #{pmc.ljust(22)} # missing in #{month}\n"
  end

  # add new 'rejected' entries
  (rejected - missing - existing).each do |pmc|
    block += "    #{pmc.ljust(22)} # not accepted in #{month}\n"
  end

  # add new 'established' entries and remove 'terminated' entries
  month = (date + 91).strftime('%B')
  todos.each do |resolution|
    pmc = resolution['display_name']
    if resolution['action'] == 'terminate'
      block.sub! %r{^    #{Regexp.escape(pmc).ljust(22)} # .*\n}, ''
    elsif resolution['action'] == 'establish' and not existing.include? pmc
      block += "    #{pmc.ljust(22)} # new, monthly through #{month}\n"
    end
  end

  # replace/append block
  if next_month.include? '#'
    next_month[/(.*#.*\n)+/] = block.split("\n").sort.join("\n")
  else
    next_month += block
  end

  # replace next month section
  contents[/Next month.*?\n\n/m] = next_month + "\n\n"

  # return result
  contents
end
update_roster(contents, cttee, people, action) click to toggle source

update roster for a project Intended for use in ASF::SVN.update() block

contents = current contents (normally provided by ASF::SVN.update); will be updated cttee = committee id (lower case) people = array of Person objects action = add|remove Note: ignores duplicate changes (e.g. if person to add is already present)

# File lib/whimsy/asf/committee.rb, line 252
def self.update_roster(contents, cttee, people, action)
  found = false
  contents.scan(/^\* (?:.|\n)*?\n\s*?\n/).each do |block|
    # find committee
    next unless ASF::Committee.find(block[/\* (.*?)\s+\(/, 1]).id == cttee

    # split block into lines
    lines = block.strip.split("\n")
    header = lines.shift
    # get the first line and use that to calculate the default offsets to use
    # This is done to avoid changing the spacing needlessly
    sample = lines.first
    namelen = NAMELEN # original
    nameaddrlen = NAMEADDRLEN # original
    # N.B. 4 spaces are assumed at the start
    if sample =~ %r{^    (\S.+) (<\S+?>\s+)\[}
      namelen = $1.size
      nameaddrlen = namelen + $2.size
    end
    # add or remove people
    # There are generally more people already in a PMC than are added or removed,
    # so try to scan the lines once
    # Get list of emails affected
    yyyymmdd = Time.new.gmtime.strftime('[%Y-%m-%d]')
    # gather list of potential new entries (some may be removed below)
    newentries = people.map do |person|
      [person.public_name, "<#{person.id}@apache.org>", yyyymmdd]
    end.to_a
    if action == 'add'
      # parse the lines so we can use format_pmc to recreate the entry, adjusting lengths if need be
      parsed = lines.map do |line|
        m = line.match(%r{^    (\S.+?) (<[^>]+>)\s+(\[\d.+)})
        if m
          newentries.reject! {|entry| m[2] == entry[1]}
          [m[1].strip, m[2], m[3]]
        else
          raise ArgumentError.new("Unexpected entry: #{line}")
        end
      end
      parsed += newentries
      lines = format_pmc(parsed, namelen, nameaddrlen)
    elsif action == 'remove'
      lines.reject! {|line| newentries.any? {|entry| line.include? entry[1]}}
    else
      raise ArgumentError.new("Expected action=[add|remove], found '#{action}'")
    end

    # replace committee block with new information
    contents.sub! block, ([header] + lines.sort).join("\n") + "\n\n"
    found = true
    break
  end
  raise ArgumentError.new("Could not find project id='#{cttee}'") unless found
  contents
end

Public Instance Methods

add_committers(people) click to toggle source

add people as committers of a project. This information is stored in LDAP using a members attribute.

# File lib/whimsy/asf/ldap.rb, line 1409
def add_committers(people)
  ASF::Project.find(name).add_members(people)
end
add_owners(people) click to toggle source

add people as owners of a project in LDAP

# File lib/whimsy/asf/ldap.rb, line 1403
def add_owners(people)
  ASF::Project.find(name).add_owners(people)
end
chair() click to toggle source

returns the (first) chair as an instance of the ASF::Person class.

# File lib/whimsy/asf/committee.rb, line 624
def chair
  Committee.load_committee_info
  if @chairs.length >= 1
    ASF::Person.find(@chairs.first[:id])
  else
    nil
  end
end
committerids() click to toggle source

List of committer ids for this committee Takes info from Project

# File lib/whimsy/asf/ldap.rb, line 1388
def committerids
  ASF::Project.find(name).memberids
end
committers() click to toggle source

List of committers for this committee. Data is obtained from LDAP. This data is generally stored in an attribute named member. Takes info from Project

# File lib/whimsy/asf/ldap.rb, line 1382
def committers
  ASF::Project.find(name).members
end
createTimestamp() click to toggle source

Date this committee was initially created in LDAP. defer to Project; must have called project.preload

# File lib/whimsy/asf/ldap.rb, line 1362
def createTimestamp
  ASF::Project[name].createTimestamp
end
description() click to toggle source

description for this committee.

# File lib/whimsy/asf/committee.rb, line 713
def description
  meta = ASF::Committee.metadata(name)
  meta[:description] if meta
end
display_name() click to toggle source

Version of name suitable for display purposes. Typically in uppercase. Data is sourced from committee-info.txt.

# File lib/whimsy/asf/committee.rb, line 635
def display_name
  Committee.load_committee_info
  @display_name || name
end
display_name=(name) click to toggle source

setter for display_name, should only be used by ASF::Committee.load_committee_info

# File lib/whimsy/asf/committee.rb, line 642
def display_name=(name)
  @display_name ||= name
end
dn() click to toggle source

Designated Name from LDAP

# File lib/whimsy/asf/ldap.rb, line 1414
def dn
  @dn ||= ASF::Project.find(name).dn
end
info=(list) click to toggle source

setter for display_name, should only be used by ASF::Committee.load_committee_info

# File lib/whimsy/asf/committee.rb, line 656
def info=(list)
  @info = list
end
mail_list() click to toggle source

mailing list for this committee. Generally returns the first name in the dns (e.g. whimsical). If so, it can be prefixed by a number of list names (e.g. dev, private) and .apache.org is to be appended. In some cases, the name contains an @ sign and is the full name for the mail list.

# File lib/whimsy/asf/mail.rb, line 340
def mail_list
  case name.downcase
  when 'comdev'
    'community'
  when 'httpcomponents'
    'hc'
  when 'whimsy'
    'whimsical'

  when 'brand'
    'trademarks@apache.org'
  when 'infrastructure'
    'infra'
  when 'dataprivacy'
    'privacy@apache.org'
  when 'legalaffairs' # Not sure what uses this
    'legal-internal@apache.org'
  when 'legal' # This seems to be used by the board agenda
    'legal-private@apache.org'
  when 'fundraising'
    'fundraising-private@apache.org'
  when 'marketingandpublicity'
    'press@apache.org'
  # now using private@tac.apache.org
  # when 'tac'
  #   'travel-assistance@apache.org'
  when 'w3crelations'
    'w3c@apache.org'
  when 'concom'
    'planners@apachecon.com'
  when 'publicaffairs'
    'public-affairs-private@apache.org'
  else
    name.downcase
  end
end
modifyTimestamp() click to toggle source

Date this committee was last modified in LDAP. defer to Project; must have called project.preload

# File lib/whimsy/asf/ldap.rb, line 1356
def modifyTimestamp
  ASF::Project[name].modifyTimestamp
end
names() click to toggle source

hash of availid => public_name for members (owners) of this committee Data is obtained from committee-info.txt.

# File lib/whimsy/asf/committee.rb, line 662
def names
  Committee.load_committee_info
  Hash[@roster.map {|id, info| [id, info[:name]]}]
end
nonpmc?() click to toggle source

if true, this committee is not a PMC. Data is obtained from committee-info.txt.

# File lib/whimsy/asf/committee.rb, line 669
def nonpmc?
  Committee.load_committee_info # ensure data is there
  Committee.nonpmcs.include? self
end
ownerids() click to toggle source

List of owner ids for this committee Takes info from Project

# File lib/whimsy/asf/ldap.rb, line 1375
def ownerids
  ASF::Project.find(name).ownerids
end
owners() click to toggle source

List of owners for this committee, i.e. people who are members of the committee and have update access. Data is obtained from LDAP. Takes info from Project

# File lib/whimsy/asf/ldap.rb, line 1369
def owners
  ASF::Project.find(name).owners
end
pmc?() click to toggle source

if true, this committee is a PMC. Data is obtained from committee-info.txt.

# File lib/whimsy/asf/committee.rb, line 676
def pmc?
  Committee.load_committee_info # ensure data is there
  Committee.pmcs.include? self
end
remove_committers(people) click to toggle source

remove people as members of a project in LDAP

# File lib/whimsy/asf/ldap.rb, line 1398
def remove_committers(people)
  ASF::Project.find(name).remove_members(people)
end
remove_owners(people) click to toggle source

remove people as owners of a project in LDAP

# File lib/whimsy/asf/ldap.rb, line 1393
def remove_owners(people)
  ASF::Project.find(name).remove_owners(people)
end
report() click to toggle source

when this committee is next expected to report. May be a string containing values such as “Next month: missing in May”, “Next month: new, monthly through July”. Or may be a list of months, separated by commas. Data is obtained from committee-info.txt.

# File lib/whimsy/asf/committee.rb, line 650
def report
  @report || @schedule
end
site() click to toggle source

website for this committee.

# File lib/whimsy/asf/committee.rb, line 707
def site
  meta = ASF::Committee.metadata(name)
  meta[:site] if meta
end