class ASF::Podling

Represents a podling, drawing information from both podlings.xml and LDAP.

Attributes

champion[RW]

userid of the champion, from podlings.xml

description[RW]

description of the podling, from podlings.xml

mentors[RW]

list of userids of the mentors, from podlings.xml

monthly[RW]

if reporting monthly, a list of months reports are expected. Can also ge nil or an empty list. From podlings.xml.

name[W]

name of the podling, from podlings.xml

reporting[RW]

list of months in the normal reporting schedule for this podling.

resource[RW]

name of the podling, from podlings.xml

resourceAliases[RW]

array of aliases for the podling, from podlings.xml

status[RW]

status of the podling, from podlings.xml. Valid values are current, graduated, or retired.

Public Class Methods

current() click to toggle source

list of current podlings

# File lib/whimsy/asf/podling.rb, line 164
def self.current
  list.select { |podling| podling.status == 'current' }
end
each(&block) click to toggle source

provide a list of podling names and descriptions

# File lib/whimsy/asf/podling.rb, line 192
def self.each(&block)
  list.each { |podling| block.call podling.name, podling }
end
find(name) click to toggle source

find a podling by name

# File lib/whimsy/asf/podling.rb, line 175
def self.find(name)
  list.find { |podling| podling.name == name }
end
list() click to toggle source

list of all podlings, regardless of status

# File lib/whimsy/asf/podling.rb, line 139
def self.list
  incubator_content = ASF::SVN['asf/incubator/public/trunk/content']
  podlings_xml = "#{incubator_content}/podlings.xml"

  # see if there is a later version
  cache = ASF::Config.get(:cache)
  if File.exist? "#{cache}/podlings.xml"
    if File.mtime("#{cache}/podlings.xml") > File.mtime(podlings_xml)
      podlings_xml = "#{cache}/podlings.xml"
    end
  end

  if @mtime != File.mtime(podlings_xml)
    @list = []
    podlings = Nokogiri::XML(File.read(podlings_xml))
    podlings.search('podling').map do |node|
      @list << new(node)
    end
    @mtime = File.mtime(podlings_xml)
  end

  @list
end
mtime() click to toggle source

last modified time of podlings.xml in the local working directory, as of the last time list was called.

# File lib/whimsy/asf/podling.rb, line 170
def self.mtime
  @mtime
end
namesearch() click to toggle source

parse (and cache) names mentioned in podlingnamesearches

# File lib/whimsy/asf/podling.rb, line 350
def self.namesearch
  # cache JIRA response
  cache = "#{ASF::Config.get(:cache)}/pns.jira"
  if not File.exist?(cache) or File.mtime(cache) < Time.now - 300
    query = 'https://issues.apache.org/jira/rest/api/2/search?' +
        'maxResults=1000&' +
        'jql=project=PODLINGNAMESEARCH&fields=summary,resolution,customfield_12310520'
    begin
      File.write cache, Net::HTTP.get(URI(query))
    rescue => e
      Wunderbar.warn "ASF::Podling.namesearch: " + e.message
    end
  end

  # parse JIRA titles for proposed name
  issues = JSON.parse(File.read(cache))['issues'].map do |issue|
    title = issue['fields']['summary'].strip.gsub(/\s+/, ' ')
    name = issue['fields']['customfield_12310520']

    if name
      name.sub! /^Apache\s+/, ''
      name.gsub! /\s+\(.*?\)/, ''
      name = nil if name =~ /^This/ or name !~ /[A-Z]/
    end

    name ||= title[/"Apache ([a-zA-Z].*?)"/, 1]
    name ||= title[/'Apache ([a-zA-Z].*?)'/, 1]
    name ||= title[/.*Apache ([A-Z]\S*)/, 1]
    name ||= title.gsub('Apache', '')[/.*\b([A-Z]\S*)/, 1]
    next unless name
    resolution = issue['fields']['resolution']
    resolution = resolution ? resolution['name'] : 'Unresolved'
    [name, {issue: issue['key'], resolution: resolution}]
  end

  issues.compact.sort_by(&:first).to_h
end
new(node) click to toggle source

create a podling from a Nokogiri node built from podlings.xml

# File lib/whimsy/asf/podling.rb, line 52
def initialize(node)
  @name = node['name']
  @resource = node['resource']
  @sponsor = node['sponsor']
  # Needed for matching against mailing list names 
  @resourceAliases = []
  @resourceAliases = node['resourceAliases'].split(/,\s*/) if node['resourceAliases']
  @status = node['status']
  @enddate = node['enddate']
  @startdate = node['startdate']
  @description = node.at('description').text
  @mentors = node.search('mentor').map { |mentor| mentor['username'] }
  @champion = node.at('champion')['availid'] if node.at('champion')

  @reporting = node.at('reporting') if node.at('reporting')
  @monthly = @reporting.text.split(/,\s*/) if @reporting and @reporting.text

  # Note: the following optional elements are not currently processed:
  # - resolution
  # - retiring/graduating
  # The following podling attributes are not processed:
  # - longname
end
to_h() click to toggle source

return the entire list as a hash

# File lib/whimsy/asf/podling.rb, line 187
def self.to_h
  Hash[self.to_a]
end

Public Instance Methods

[](name) click to toggle source

allow attributes to be accessed as hash

# File lib/whimsy/asf/podling.rb, line 197
def [](name)
  return self.send name if self.respond_to? name
end
_match_mailname?(list, _name) click to toggle source

Match against new and old list types

# File lib/whimsy/asf/podling.rb, line 250
def _match_mailname?(list, _name)
  return true if list.start_with?("#{_name}-")
  return true if list.start_with?("incubator-#{_name}-")
end
as_hash() click to toggle source

Return the instance as a hash. Keys in the hash are: :name, :status, :description, :mentors, :startdate, :champion, :reporting, :resource, :resourceAliases, :sponsor, :duration, and :podlingStatus

# File lib/whimsy/asf/podling.rb, line 293
def as_hash # might be confusing to use to_h here?
  hash = {
      name: @name,
      status: status,
      description: description,
      mentors: mentors,
      startdate: startdate,
  }
  hash[:enddate] = enddate if enddate
  hash[:champion] = champion if champion

  # Tidy up the reporting output
  podlingStatus = self.podlingStatus
  r = @reporting
  if r.instance_of? Nokogiri::XML::Element
    group = r['group']
    hash[:reporting] = {
        group: group
    }
    hash[:reporting][:text] = r.text if r.text.length > 0
    hash[:reporting][:monthly] = r.text.split(/,\s*/) if r['monthly']
    hash[:reporting][:schedule] = self.schedule
  else
    hash[:reporting] = r if r
  end

  hash[:resource] = resource
  hash[:resourceAliases] = resourceAliases
  hash[:namesearch] = namesearch if namesearch
  hash[:sponsor] = @sponsor if @sponsor
  hash[:duration] = self.duration
  hash[:podlingStatus] = podlingStatus
  hash
end
default_status() click to toggle source

status information associated with this podling. Keys in the hash return include: :issueTracker, :wiki, :jira, :proposal, :asfCopyright, <tt>:distributionRights, :ipClearance, :sga, :website, :graduationDate, :resolution

# File lib/whimsy/asf/podling.rb, line 333
def default_status
  {
      issueTracker: 'jira',
      wiki: self.resource.upcase,
      jira: self.resource.upcase,
      proposal: 'http://wiki.apache.org/incubator/'+self.resource.capitalize+"Proposal",
      asfCopyright: nil,
      distributionRights: nil,
      ipClearance: nil,
      sga: nil,
      website: 'http://'+self.resource+'.incubator.apache.org',
      graduationDate: nil,
      resolution: nil
  }
end
dev_mail_list() click to toggle source

development mailing list associated with a given podling

# File lib/whimsy/asf/podling.rb, line 212
def dev_mail_list
  case name
    when 'climatemodeldiagnosticanalyzer'
      'dev@cmda.incubator.apache.org'
    when 'odftoolkit'
      'odf-dev@incubator.apache.org'
    when 'log4cxx2'
      'log4cxx-dev@logging.apache.org'
    else
      if ASF::Mail.lists.include? "#{name}-dev"
        "dev@#{name}.apache.org"
      elsif ASF::Mail.lists.include? "incubator-#{name}-dev"
        "#{name}-dev@incubator.apache.org"
      end
  end
end
display_name() click to toggle source

display name for this podling, originally from the name attribute in podlings.xml.

# File lib/whimsy/asf/podling.rb, line 89
def display_name
  @name || @resource
end
duration() click to toggle source

number of days in incubation

# File lib/whimsy/asf/podling.rb, line 115
def duration
  last = enddate || Date.today
  first = startdate || Date.today
  (last - first).to_i
end
enddate() click to toggle source

date this podling either retired or graduated. nil for current podlings.

# File lib/whimsy/asf/podling.rb, line 105
def enddate
  return unless @enddate
  # assume 15th (mid-month) if no day specified
  return Date.parse("#@enddate-15") if @enddate.length < 8
  Date.parse(@enddate)
rescue ArgumentError
  nil
end
id() click to toggle source

also map resource to id

# File lib/whimsy/asf/podling.rb, line 83
def id
  @resource
end
mail_list() click to toggle source

base name used in constructing mailing list name.

# File lib/whimsy/asf/mail.rb, line 204
def mail_list
  name
end
mail_list?(list) click to toggle source

Is this a podling mailing list?

# File lib/whimsy/asf/podling.rb, line 240
def mail_list?(list)
  return true if _match_mailname?(list, name())
  # Also check aliases
  @resourceAliases.each { |name|
    return true if _match_mailname?(list, name)
  }
  return false
end
members() click to toggle source

list of PPMC committers from LDAP

# File lib/whimsy/asf/podling.rb, line 207
def members
  ASF::Project.find(id).members
end
name() click to toggle source

name for this podling, originally from the resource attribute in podlings.xml.

# File lib/whimsy/asf/podling.rb, line 78
def name
  @resource
end
namesearch() click to toggle source

return podlingnamesearch for this podling

# File lib/whimsy/asf/podling.rb, line 389
def namesearch
  Podling.namesearch[display_name]
end
owners() click to toggle source

list of PPMC owners from LDAP

# File lib/whimsy/asf/podling.rb, line 202
def owners
  ASF::Project.find(id).owners
end
podlingStatus() click to toggle source

status information associated with this podling. Keys in the hash return include: :ipClearance, :sourceControl, :wiki, :jira, :proposal, :website, :news

# File lib/whimsy/asf/podling.rb, line 258
def podlingStatus
  # resource can contain '-'
  @resource.untaint if @resource =~ /\A[-\w]+\z/
  incubator_content = ASF::SVN['asf/incubator/public/trunk/content/podlings']
  resource_yml = "#{incubator_content}/#{@resource}.yml"
  if File.exist?(resource_yml)
    rawYaml = Psych.load_file(resource_yml)
    hash = { }
    hash[:sga] = rawYaml[:sga].strftime('%Y-%m-%d') if rawYaml[:sga]
    hash[:asfCopyright] = rawYaml[:asfCopyright].strftime('%Y-%m-%d') if rawYaml[:asfCopyright]
    hash[:distributionRights] = rawYaml[:distributionRights].strftime('%Y-%m-%d') if rawYaml[:distributionRights]
    hash[:ipClearance] = rawYaml[:ipClearance]
    hash[:sourceControl] = rawYaml[:sourceControl]
    hash[:wiki] = rawYaml[:wiki]
    hash[:jira] = rawYaml[:jira]
    hash[:proposal] = rawYaml[:proposal]
    hash[:website] = rawYaml[:website]
    hash[:news] = []
    for ni in rawYaml[:news]
      newsItem = {}
      newsItem[:date] = ni[:date].strftime('%Y-%m-%d')
      newsItem[:note] = ni[:note]
      hash[:news].push(newsItem)
    end if rawYaml[:news]
    hash
  else
    {news: []}
  end
end
private_mail_list() click to toggle source

private mailing list associated with a given podling

# File lib/whimsy/asf/podling.rb, line 230
def private_mail_list
  if name == 'log4cxx2'
    'private@logging.apache.org'
  else
    list = dev_mail_list
    list ? list.sub('dev', 'private') : 'private@incubator.apache.org'
  end
end
quarter() click to toggle source

three consecutive months, starting with this one

# File lib/whimsy/asf/podling.rb, line 43
def quarter
  [
      Date.today.strftime('%B'),
      Date.today.next_month.strftime('%B'),
      Date.today.next_month.next_month.strftime('%B')
  ]
end
schedule() click to toggle source

provides a concatenated reporting schedule

# File lib/whimsy/asf/podling.rb, line 134
def schedule
  self.reporting + self.monthly
end
startdate() click to toggle source

date this podling was accepted for incubation

# File lib/whimsy/asf/podling.rb, line 94
def startdate
  return unless @startdate
  # assume 15th (mid-month) if no day specified
  return Date.parse("#@startdate-15") if @startdate.length < 8
  Date.parse(@startdate)
rescue ArgumentError
  nil
end