| # Reads LDAP ou=projects and extracts member rosters for PMCs |
| # (PMC status comes from committee-info.txt) |
| # |
| # Also reads LDAP ou=groups,dc=apache,dc=org to extract some non-PMCs |
| # This is to maintain compatibility with earlier output |
| # |
| # The contents cannot be used to determine LDAP group membership |
| # |
| # Creates JSON output with the following format: |
| # |
| # { |
| # "lastTimestamp": "20160119171152Z", // most recent modifyTimestamp |
| # "groups": { |
| # "abdera": { |
| # "modifyTimestamp": "20111204095436Z", |
| # "roster": ["uid", |
| # ... |
| # ] |
| # }, |
| # ... |
| # }, |
| # } |
| # |
| |
| require_relative 'public_json_common' |
| |
| entries = {} |
| |
| # Dummy classes as Project class seems to be awkward to create easily |
| class MyProject |
| attr_accessor :modifyTimestamp |
| attr_accessor :createTimestamp |
| attr_accessor :name |
| attr_accessor :members |
| attr_accessor :owners |
| end |
| |
| class MyPerson |
| attr_accessor :name |
| def initialize(name) |
| @name=name |
| end |
| end |
| |
| groups = ASF::Group.preload # for performance |
| projects = ASF::Project.preload |
| |
| # Not projects but in original output |
| # TODO do we want them all? |
| # These will be extracted from groups if not in projects |
| EXTRAS = %w(apsite committers member concom infra security) |
| |
| # These are the ones that will be generated |
| WANTED = ASF::Committee.pmcs.map(&:name) + EXTRAS |
| |
| if projects.empty? |
| Wunderbar.error "No results retrieved, output not created" |
| exit 0 |
| end |
| lastStamp = '' |
| |
| # Add the non-project entries from the groups |
| ALREADY = projects.keys.map(&:name) |
| groups.select{|g| EXTRAS.include? g.name}.each do |group,data| |
| next if ALREADY.include?(group.name) |
| project = MyProject.new |
| project.name = group.name |
| project.createTimestamp = group.createTimestamp |
| project.modifyTimestamp = group.modifyTimestamp |
| project.members = group.members.map{|p| MyPerson.new(p.name)} |
| project.owners = [] |
| projects[project] = [] |
| end |
| |
| projects.keys.sort_by {|a| a.name}.each do |project| |
| next unless WANTED.include? project.name |
| m = [] |
| createTimestamp = project.createTimestamp |
| modifyTimestamp = project.modifyTimestamp |
| project.members.sort_by {|a| a.name}.each do |e| |
| m << e.name |
| end |
| lastStamp = modifyTimestamp if modifyTimestamp > lastStamp |
| entries[project.name] = { |
| createTimestamp: createTimestamp, |
| modifyTimestamp: modifyTimestamp, |
| roster: m |
| } |
| end |
| |
| info = { |
| # Is there a use case for the last createTimestamp ? |
| lastTimestamp: lastStamp, |
| groups: entries, |
| } |
| |
| public_json_output(info) |
| |
| if changed? and @old_file |
| # for validating UIDs |
| uids = ASF::Person.list().map(&:id) |
| entries.each do |name, entry| |
| entry[:roster].each do |id| |
| Wunderbar.warn "#{name}: unknown uid '#{id}'" unless uids.include?(id) |
| end |
| end |
| end |