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 508 def self._list(status) list.select { |podling| status == 'all' or podling.status == status } end
Source
# File lib/whimsy/asf/podling.rb, line 512 def self._listids(status) self._list(status).map(&:id) end
Source
# File lib/whimsy/asf/podling.rb, line 237 def self.all self._list('all') end
list of all podlings
Source
# File lib/whimsy/asf/podling.rb, line 242 def self.allids self._listids('all') end
list of all podling ids
Source
# File lib/whimsy/asf/podling.rb, line 207 def self.current self._list('current') end
list of current podlings
Source
# File lib/whimsy/asf/podling.rb, line 212 def self.currentids self._listids('current') end
list of current podling ids
Source
# File lib/whimsy/asf/podling.rb, line 280 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 253 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 217 def self.graduated self._list('graduated') end
list of graduated podlings
Source
# File lib/whimsy/asf/podling.rb, line 222 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 202 def self.list_with_status self.list.map {|pod| [pod.id, pod.status]}.to_h end
hash of podlings with status
Source
# File lib/whimsy/asf/podling.rb, line 248 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 456 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 227 def self.retired self._list('retired') end
list of retired podlings
Source
# File lib/whimsy/asf/podling.rb, line 232 def self.retiredids self._listids('retired') end
list of retired podling ids
Source
# File lib/whimsy/asf/podling.rb, line 275 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 285 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 348 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 389 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 432 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 314 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 299 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 304 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 338 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 295 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 502 def namesearch Podling.namesearch[display_name] end
return podlingnamesearch for this podling
Source
# File lib/whimsy/asf/podling.rb, line 290 def owners ASF::Project.find(id).owners end
list of PPMC owners from LDAP
Source
# File lib/whimsy/asf/podling.rb, line 356 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 328 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)