class ASF::Podling
Represents a podling, drawing information from both podlings.xml and LDAP
.
Constants
- NAME_FIXES
-
Override Proposed Names that are wrong
Attributes
userid of the champion, from podlings.xml
description of the podling, from podlings.xml
list of userids of the mentors, from podlings.xml
if reporting monthly, a list of months reports are expected. Can also ge nil
or an empty list. From podlings.xml.
name of the podling, from podlings.xml
<resolution link=“”>, from podlings.xml
<resolution tlp=“”>, from podlings.xml
<resolution url=“”>, from podlings.xml
name of the podling, from podlings.xml
array of aliases for the podling, from podlings.xml
status of the podling, from podlings.xml. Valid values are current
, graduated
, or retired
.
Public Class Methods
Source
# File lib/whimsy/asf/podling.rb, line 493 def self._list(status) list.select { |podling| podling.status == status } end
Source
# File lib/whimsy/asf/podling.rb, line 497 def self._listids(status) list.select { |podling| podling.status == status }.map(&:id) end
Source
# File lib/whimsy/asf/podling.rb, line 202 def self.current self._list('current') end
list of current podlings
Source
# File lib/whimsy/asf/podling.rb, line 207 def self.currentids self._listids('current') end
list of current podling ids
Source
# File lib/whimsy/asf/podling.rb, line 265 def self.each(&block) list.each { |podling| block.call podling.name, podling } end
provide a list of podling names and descriptions
Source
# File lib/whimsy/asf/podling.rb, line 238 def self.find(name) name = name.downcase result = list.find do |podling| podling.name == name or podling.display_name.downcase == name or podling.resourceAliases.any? {|aname| aname.downcase == name} end result ||= list.find do |podling| podling.resource == name or podling.tlp_name.downcase == name end end
find a podling by name
Source
# File lib/whimsy/asf/podling.rb, line 212 def self.graduated self._list('graduated') end
list of graduated podlings
Source
# File lib/whimsy/asf/podling.rb, line 217 def self.graduatedids self._listids('graduated') end
list of graduated podling ids
Source
# File lib/whimsy/asf/podling.rb, line 175 def self.list incubator_content = ASF::SVN['incubator-content'] podlings_xml = File.join(incubator_content, 'podlings.xml') # see if there is a later version cache = ASF::Config.get(:cache) if File.exist? File.join(cache, 'podlings.xml') if File.mtime(File.join(cache, 'podlings.xml')) > File.mtime(podlings_xml) podlings_xml = File.join(cache, 'podlings.xml') end end if @mtime != File.mtime(podlings_xml) @list = [] podlings = Nokogiri::XML(File.read(podlings_xml)) # check for errors as they adversely affect the generated output raise Exception.new(podlings.errors.inspect) if podlings.errors.size > 0 podlings.search('podling').map do |node| @list << new(node) end @mtime = File.mtime(podlings_xml) end @list end
list of all podlings, regardless of status
Source
# File lib/whimsy/asf/podling.rb, line 233 def self.mtime @mtime end
last modified time of podlings.xml in the local working directory, as of the last time list was called.
Source
# File lib/whimsy/asf/podling.rb, line 441 def self.namesearch # cache JIRA response cache = File.join(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_12310521' begin res = Net::HTTP.get_response(URI(query)) res.value() # Raises error if not OK file = File.new(cache, 'wb') # Allow for non-UTF-8 chars file.write res.body rescue StandardError => e Wunderbar.warn 'ASF::Podling.namesearch: ' + e.message FileUtils.touch cache # Don't try again for a while end end # parse JIRA titles for proposed name issues = JSON.parse(File.read(cache))['issues'].map do |issue| resolution = issue['fields']['resolution'] resolution = resolution ? resolution['name'] : 'Unresolved' # Ignore duplicates and abandoned entries etc. # PODLINGNAMESEARCH-9 is resolved as 'Not A Problem': this means it is cleared for use next unless %w{Fixed Unresolved Resolved Implemented}.include?(resolution) || issue['key'] == 'PODLINGNAMESEARCH-9' name = issue['fields']['customfield_12310521'] if name name.sub!(/^Apache\s+/, '') name.gsub!(/\s+\(.*?\)/, '') # Fix up incorrect 'Proposed Name' entries name = NAME_FIXES[name] || name name = nil if name =~ /^\s*This/ or name !~ /[A-Za-z]{3}/ or name =~ %r{^N/A} end next unless name [name, {issue: issue['key'], resolution: resolution}] end issues.compact.sort_by(&:first).to_h end
parse (and cache) names mentioned in podlingnamesearches Note: customfield_12310520 = ‘Podling’, customfield_12310521 = ‘Proposed Name’
Source
# File lib/whimsy/asf/podling.rb, line 57 def initialize(node) @mtime = nil @name = node['name'] @resource = node['resource'] # Validate resource for later use resource can contain '-' and '.' (lucene.net) raise ArgumentError, "Invalid resource #{@resource}" unless @resource =~ /\A[-.\w]+\z/ @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') || nil # ensure variable is defined @monthly = @reporting&.text&.split(/,\s*/) res = node.at('resolution') if res @resolutionLink = res.attr('link') @resolutionURL = res.attr('url') @resolutionTLP = res.attr('tlp') else @resolutionLink = nil @resolutionURL = nil @resolutionTLP = nil end # Note: the following optional elements are not currently processed: # - resolution (except for resolution/@link) # - retiring/graduating # The following podling attributes are not processed: # - longname end
create a podling from a Nokogiri node built from podlings.xml
Source
# File lib/whimsy/asf/podling.rb, line 222 def self.retired self._list('retired') end
list of retired podlings
Source
# File lib/whimsy/asf/podling.rb, line 227 def self.retiredids self._listids('retired') end
list of retired podling ids
Source
# File lib/whimsy/asf/podling.rb, line 260 def self.to_h Hash[self.to_a] end
return the entire list as a hash
Public Instance Methods
Source
# File lib/whimsy/asf/podling.rb, line 270 def [](name) return self.send name if self.respond_to? name end
allow attributes to be accessed as hash
Source
# File lib/whimsy/asf/podling.rb, line 333 def _match_mailname?(list, name) return true if list.start_with?("#{name}-") return true if list.start_with?("incubator-#{name}-") end
Match against new and old list types
Source
# File lib/whimsy/asf/podling.rb, line 374 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 elsif r hash[:reporting] = 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[:resolutionLink] = resolutionLink if resolutionLink hash[:resolutionURL] = resolutionURL if resolutionURL hash[:resolutionTLP] = resolutionTLP if resolutionTLP hash end
Return the instance as a hash. Keys in the hash are: :name
, :status
, :description
, :mentors
, :startdate
, :champion
, :reporting
, :resource
, :resourceAliases
, :sponsor
, :duration
, and :podlingStatus
Source
# File lib/whimsy/asf/podling.rb, line 417 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
status information associated with this podling. Keys in the hash return include: :issueTracker
, :wiki
, :jira
, :proposal
, :asfCopyright, <tt>:distributionRights
, :ipClearance
, :sga
, :website
, :graduationDate
, :resolution
Source
# File lib/whimsy/asf/podling.rb, line 299 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 "dev@#{name}.apache.org" end end
development mailing list associated with a given podling
Source
# File lib/whimsy/asf/podling.rb, line 108 def display_name @name || @resource end
display name for this podling, originally from the name attribute in podlings.xml.
Source
# File lib/whimsy/asf/podling.rb, line 151 def duration last = enddate || Date.today first = startdate || Date.today (last - first).to_i end
number of days in incubation
Source
# File lib/whimsy/asf/podling.rb, line 141 def enddate return unless @enddate and @enddate.length >= 7 # assume 15th (mid-month) if no day specified return Date.parse("#{@enddate}-15") if @enddate.length == 7 Date.parse(@enddate) rescue ArgumentError nil end
date this podling either retired or graduated. nil
for current podlings.
Source
# File lib/whimsy/asf/podling.rb, line 121 def graduated? @status == 'graduated' end
Source
# File lib/whimsy/asf/podling.rb, line 284 def hasLDAP? ASF::Project.find(id).hasLDAP? end
Source
# File lib/whimsy/asf/podling.rb, line 102 def id @resource end
also map resource to id
Source
# File lib/whimsy/asf/podling.rb, line 289 def mail_list case name.downcase when 'odftoolkit' 'odf' else name.downcase end end
base name used in constructing mailing list name.
Source
# File lib/whimsy/asf/podling.rb, line 323 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
Is this a podling mailing list?
Source
# File lib/whimsy/asf/podling.rb, line 280 def members ASF::Project.find(id).members end
list of PPMC committers from LDAP
Source
# File lib/whimsy/asf/podling.rb, line 97 def name @resource end
name for this podling, originally from the resource attribute in podlings.xml.
Source
# File lib/whimsy/asf/podling.rb, line 487 def namesearch Podling.namesearch[display_name] end
return podlingnamesearch for this podling
Source
# File lib/whimsy/asf/podling.rb, line 275 def owners ASF::Project.find(id).owners end
list of PPMC owners from LDAP
Source
# File lib/whimsy/asf/podling.rb, line 341 def podlingStatus incubator_content = ASF::SVN['incubator-podlings'] resource_yml = File.join(incubator_content, "#{@resource}.yml") if File.exist?(resource_yml) rawYaml = Psych.load_file(resource_yml, permitted_classes: [Date, Symbol]) hash = { } hash[:sga] = rawYaml[:sga].strftime('%Y-%m-%d') if rawYaml[:sga]&.class == Date hash[:asfCopyright] = rawYaml[:asfCopyright].strftime('%Y-%m-%d') if rawYaml[:asfCopyright]&.class == Date hash[:distributionRights] = rawYaml[:distributionRights].strftime('%Y-%m-%d') if rawYaml[:distributionRights]&.class == Date hash[:ipClearance] = rawYaml[:ipClearance].strftime('%Y-%m-%d') if rawYaml[:ipClearance]&.class == Date hash[:sourceControl] = rawYaml[:sourceControl] hash[:wiki] = rawYaml[:wiki] hash[:jira] = rawYaml[:jira] hash[:proposal] = rawYaml[:proposal] hash[:website] = rawYaml[:website] hash[:news] = [] rawYaml[:news]&.each do |ni| newsItem = {} newsItem[:date] = ni[:date].strftime('%Y-%m-%d') if ni[:date]&.class == Date newsItem[:note] = ni[:note] hash[:news].push(newsItem) end hash else {news: [], website: "http://#{self.resource}.incubator.apache.org"} end end
status information associated with this podling. Keys in the hash return include: :ipClearance
, :sourceControl
, :wiki
, :jira
, :proposal
, :website
, :news
Source
# File lib/whimsy/asf/podling.rb, line 313 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
private mailing list associated with a given podling
Source
# File lib/whimsy/asf/podling.rb, line 39 def quarter [ Date.today.strftime('%B'), Date.today.next_month.strftime('%B'), Date.today.next_month.next_month.strftime('%B') ] end
three consecutive months, starting with this one
Source
# File lib/whimsy/asf/podling.rb, line 158 def reporting if @reporting.instance_of? Nokogiri::XML::Element group = @reporting['group'] @reporting = %w(January April July October) if group == '1' @reporting = %w(February May August November) if group == '2' @reporting = %w(March June September December) if group == '3' end @reporting end
lazy evaluation of reporting
Source
# File lib/whimsy/asf/podling.rb, line 170 def schedule self.reporting + self.monthly end
provides a concatenated reporting schedule
Source
# File lib/whimsy/asf/podling.rb, line 130 def startdate return unless @startdate and @startdate.length >= 7 # "YYYY-MM" # assume 15th (mid-month) if no day specified return Date.parse("#{@startdate}-15") if @startdate.length == 7 Date.parse(@startdate) rescue ArgumentError nil end
date this podling was accepted for incubation
Source
# File lib/whimsy/asf/podling.rb, line 113 def tlp_name @resolutionLink || name end
TLP name (name differ from podling name)