summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThom May <thom@chef.io>2015-12-16 16:07:28 +0000
committerThom May <thom@may.lt>2015-12-16 16:07:28 +0000
commitecda0379790155a4c3b8dc253e9bfeb55631a289 (patch)
treee1e53ee6454e9d89420ff2ea8ed7eb75d4b55a5b
parent3c679e1a1de7cdef58567f9b544e307b02f439ba (diff)
downloadohai-tm/maintainers.tar.gz
Maintainers file for ohaitm/maintainers
-rw-r--r--.gitignore1
-rw-r--r--Gemfile8
-rw-r--r--MAINTAINERS.toml112
-rw-r--r--Rakefile1
-rw-r--r--tasks/maintainers.rb200
5 files changed, 322 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index f46c0cdc..f5f6f6f4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
*.sw?
Gemfile.lock
+MAINTAINERS.md
pkg/
tmp/
coverage/
diff --git a/Gemfile b/Gemfile
index 20ed5cd2..c7b97a84 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,6 +2,14 @@ source "https://rubygems.org"
gemspec
+group :maintenance do
+ gem "tomlrb"
+
+ # To sync maintainers with github
+ gem "octokit"
+ gem "netrc"
+end
+
group :development do
gem "chef", github: "chef/chef", branch: "master"
diff --git a/MAINTAINERS.toml b/MAINTAINERS.toml
new file mode 100644
index 00000000..1bfe64da
--- /dev/null
+++ b/MAINTAINERS.toml
@@ -0,0 +1,112 @@
+#
+# This file is structured to be consumed by both humans and computers.
+# To update the generated Markdown, run `bundle exec rake maintainers:generate`
+# It is a TOML document containing Markdown
+#
+[Preamble]
+ title = "Maintainers"
+ text = """
+This file lists how the Ohai project is maintained. When making changes to the system, this
+file tells you who needs to review your patch - you need a simple majority of maintainers
+for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need
+to not receive a veto from a Lieutenant or the Project Lead.
+
+Check out [How Chef is Maintained](https://github.com/opscode/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained) for details on the process, how to become
+a maintainer, lieutenant, or the project lead.
+"""
+
+[Org]
+ [Org.Lead]
+ title = "Project Lead"
+ person = "adamhjk"
+
+ [Org.Components]
+ title = "Components"
+
+ [Org.Components.Core]
+ title = "Ohai"
+ team = "ohai-core"
+ text = """
+Maintainers of Ohai
+"""
+
+ lieutenant = "thommay"
+
+ maintainers = [
+ "btm",
+ "coderanger",
+ "danielsdeleo",
+ "fujin",
+ "jaymzh",
+ "jaym",
+ "jonlives",
+ "lamont-granquist",
+ "mcquin",
+ "smurawski",
+ "tyler-ball",
+ "ranjib",
+ "mwrock"
+ ]
+
+[people]
+ [people.adamhjk]
+ Name = "Adam Jacob"
+ GitHub = "adamhjk"
+
+ [people.btm]
+ Name = "Bryan McLellan"
+ GitHub = "btm"
+
+ [people.danielsdeleo]
+ Name = "Daniel DeLeo"
+ GitHub = "danielsdeleo"
+
+ [people.fujin]
+ Name = "AJ Christensen"
+ GitHub = "fujin"
+
+ [people.jaymzh]
+ Name = "Phil Dibowitz"
+ GitHub = "jaymzh"
+
+ [people.jaym]
+ Name = "Jay Mundrawala"
+ GitHub = "jaym"
+
+ [people.jonlives]
+ Name = "Jon Cowie"
+ GitHub = "jonlives"
+
+ [people.lamont-granquist]
+ Name = "Lamont Granquist"
+ GitHub = "lamont-granquist"
+
+ [people.mcquin]
+ Name = "Claire McQuin"
+ GitHub = "mcquin"
+
+ [people.ranjib]
+ Name = "Ranjib Dey"
+ GitHub = "ranjib"
+
+ [people.smurawski]
+ Name = "Steven Murawski"
+ GitHub = "smurawski"
+
+ [people.thommay]
+ Name = "Thom May"
+ GitHub = "thommay"
+ IRC = "thom"
+ Twitter = "thommay"
+
+ [people.tyler-ball]
+ Name = "Tyler Ball"
+ GitHub = "tyler-ball"
+
+ [people.coderanger]
+ Name = "Noah Kantrowitz"
+ GitHub = "coderanger"
+
+ [people.mwrock]
+ Name = "Matt Wrock"
+ GitHub = "mwrock"
diff --git a/Rakefile b/Rakefile
index a2ee35b6..4c89ab26 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,6 +1,7 @@
require "bundler/gem_tasks"
require 'date'
require 'ohai/version'
+require_relative 'tasks/maintainers'
begin
require 'rspec/core/rake_task'
diff --git a/tasks/maintainers.rb b/tasks/maintainers.rb
new file mode 100644
index 00000000..53f3fdd8
--- /dev/null
+++ b/tasks/maintainers.rb
@@ -0,0 +1,200 @@
+#
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'rake'
+
+SOURCE = File.join(File.dirname(__FILE__), "..", "MAINTAINERS.toml")
+TARGET = File.join(File.dirname(__FILE__), "..", "MAINTAINERS.md")
+
+# The list of repositories that teams should own
+REPOSITORIES = ["chef/chef", "chef/chef-census", "chef/chef-repo",
+ "chef/client-docs", "chef/ffi-yajl", "chef/libyajl2-gem",
+ "chef/mixlib-authentication", "chef/mixlib-cli",
+ "chef/mixlib-config", "chef/mixlib-install", "chef/mixlib-log",
+ "chef/mixlib-shellout", "chef/ohai", "chef/omnibus-chef"]
+
+begin
+ require 'tomlrb'
+ require 'octokit'
+ require 'pp'
+ task :default => :generate
+
+ namespace :maintainers do
+ desc "Generate MarkDown version of MAINTAINERS file"
+ task :generate do
+ out = "<!-- This is a generated file. Please do not edit directly -->\n\n"
+ out << "# " + source["Preamble"]["title"] + "\n\n"
+ out << source["Preamble"]["text"] + "\n"
+
+ # The project lead is a special case
+ out << "# " + source["Org"]["Lead"]["title"] + "\n\n"
+ out << format_person(source["Org"]["Lead"]["person"]) + "\n\n"
+
+ out << format_components(source["Org"]["Components"])
+ File.open(TARGET, "w") { |fn|
+ fn.write out
+ }
+ end
+ end
+
+ def github
+ @github ||= Octokit::Client.new(:netrc => true)
+ end
+
+ def source
+ @source ||= Tomlrb.load_file SOURCE
+ end
+
+ def teams
+ @teams ||= {"client-maintainers" => {"title" => "Client Maintainers"}}
+ end
+
+ def add_members(team, name)
+ teams["client-maintainers"]["members"] ||= []
+ teams["client-maintainers"]["members"] << name
+ teams[team] ||= {}
+ teams[team]["members"] ||= []
+ teams[team]["members"] << name
+ end
+
+ def set_team_title(team, title)
+ teams[team] ||= {}
+ teams[team]["title"] = title
+ end
+
+ def gh_teams
+ @gh_teams ||= {}
+ end
+
+ # we have to resolve team names to ids. While we're at it, we can get the privacy
+ # setting, so we know whether we need to update it
+ def get_github_teams
+ github.org_teams("chef").each do |team|
+ gh_teams[team[:slug]] = {"id" => team[:id], "privacy" => team[:privacy]}
+ end
+ end
+
+ def get_github_team(team)
+ github.team_members(gh_teams[team]["id"]).map do |member|
+ member[:login]
+ end.sort.uniq.map(&:downcase)
+ rescue
+ []
+ end
+
+ def create_team(team)
+ puts "creating new github team: #{team} with title: #{teams[team]["title"]} "
+ t = github.create_team("chef", name: team, description: teams[team]["title"],
+ privacy: "closed", repo_names: REPOSITORIES,
+ accept: "application/vnd.github.ironman-preview+json")
+ gh_teams[team] = { "id" => t[:id], "privacy" => t[:privacy] }
+ end
+
+ def compare_teams(current, desired)
+ # additions are the subtraction of the current state from the desired state
+ # deletions are the subtraction of the desired state from the current state
+ [desired - current, current - desired]
+ end
+
+ def prepare_teams(cmp)
+ %w(text paths).each { |k| cmp.delete(k) }
+ if cmp.key?("team")
+ team = cmp.delete("team")
+ add_members(team, cmp.delete("lieutenant")) if cmp.key?("lieutenant")
+ add_members(team, cmp.delete("maintainers")) if cmp.key?("maintainers")
+ set_team_title(team, cmp.delete("title"))
+ else
+ %w(maintainers lieutenant title).each { |k| cmp.delete(k) }
+ end
+ cmp.each { |_k, v| prepare_teams(v) }
+ end
+
+ def update_team(team, additions, deletions)
+ create_team(team) unless gh_teams.key?(team)
+ update_team_privacy(team)
+ add_team_members(team, additions)
+ remove_team_members(team, deletions)
+ rescue
+ puts "failed for #{team}"
+ end
+
+ def update_team_privacy(team)
+ return if gh_teams[team]["privacy"] == "closed"
+ puts "Setting #{team} privacy to closed from #{gh_teams[team]["privacy"]}"
+ github.update_team(gh_teams[team]["id"], privacy: "closed",
+ accept: "application/vnd.github.ironman-preview+json")
+ end
+
+ def add_team_members(team, additions)
+ additions.each do |member|
+ puts "Adding #{member} to #{team}"
+ github.add_team_membership(gh_teams[team]["id"], member, role: "member",
+ accept: "application/vnd.github.ironman-preview+json")
+ end
+ end
+
+ def remove_team_members(team, deletions)
+ deletions.each do |member|
+ puts "Removing #{member} from #{team}"
+ github.remove_team_membership(gh_teams[team]["id"], member,
+ accept: "application/vnd.github.ironman-preview+json")
+ end
+ end
+
+ def sync_teams!
+ teams.each do |name, details|
+ current = get_github_team(name)
+ desired = details["members"].flatten.sort.uniq.map(&:downcase)
+ additions, deletions = compare_teams(current, desired)
+ update_team(name, additions, deletions)
+ end
+ end
+
+ def get_person(person)
+ source["people"][person]
+ end
+
+ def format_components(cmp)
+ out = "## " + cmp.delete("title") + "\n\n"
+ out << cmp.delete("text") + "\n" if cmp.has_key?("text")
+ out << "To mention the team, use @chef/#{cmp.delete("team")}\n\n" if cmp.has_key?("team")
+ if cmp.has_key?("lieutenant")
+ out << "### Lieutenant\n\n"
+ out << format_person(cmp.delete("lieutenant")) + "\n\n"
+ end
+ out << format_maintainers(cmp.delete("maintainers")) + "\n" if cmp.has_key?("maintainers")
+ cmp.delete("paths")
+ cmp.each {|k,v| out << format_components(v) }
+ out
+ end
+
+ def format_maintainers(people)
+ o = "### Maintainers\n\n"
+ people.each do |p|
+ o << format_person(p) + "\n"
+ end
+ o
+ end
+
+ def format_person(person)
+ mnt = get_person(person)
+ "* [#{mnt["Name"]}](https://github.com/#{mnt["GitHub"]})"
+ end
+
+rescue LoadError
+ STDERR.puts "\n*** TomlRb not available.\n\n"
+end