mirror of https://github.com/grpc/grpc.git
Merge pull request #11774 from ctiller/owners
Strawman OWNERS --> CODEOWNERS scriptpull/11362/merge
commit
df4cbb1abe
24 changed files with 289 additions and 43 deletions
@ -0,0 +1,22 @@ |
|||||||
|
# Auto-generated by the tools/mkowners/mkowners.py tool |
||||||
|
# Uses OWNERS files in different modules throughout the |
||||||
|
# repository as the source of truth for module ownership. |
||||||
|
* @a11r @nicolasnoble @ctiller |
||||||
|
bazel/* @nicolasnoble @dgquintas @ctiller |
||||||
|
cmake/* @jtattermusch @a11r @nicolasnoble @ctiller |
||||||
|
doc/PROTOCOL-HTTP2.md @ejona86 @a11r @nicolasnoble @ctiller |
||||||
|
doc/interop-test-descriptions.md @ejona86 @a11r @nicolasnoble @ctiller |
||||||
|
etc/* @jboeuf @nicolasnoble @a11r @ctiller |
||||||
|
include/* @ctiller @markdroth @dgquintas @a11r @nicolasnoble |
||||||
|
src/core/* @ctiller @markdroth @dgquintas @a11r @nicolasnoble |
||||||
|
src/cpp/* @ctiller @markdroth @dgquintas @a11r @nicolasnoble |
||||||
|
src/csharp/* @jtattermusch @apolcyn @a11r @nicolasnoble @ctiller |
||||||
|
src/node/* @murgatroid99 @a11r @nicolasnoble @ctiller |
||||||
|
src/objective-c/* @muxi @makdharma @a11r @nicolasnoble @ctiller |
||||||
|
src/php/* @stanley-cheung @murgatroid99 @a11r @nicolasnoble @ctiller |
||||||
|
src/python/* @nathanielmanistaatgoogle @kpayson64 @a11r @nicolasnoble @ctiller |
||||||
|
src/ruby/* @apolcyn @murgatroid99 @a11r @nicolasnoble @ctiller |
||||||
|
tools/* @matt-kwong @jtattermusch @nicolasnoble @a11r @ctiller |
||||||
|
tools/codegen/core/* @ctiller @dgquintas @markdroth |
||||||
|
tools/dockerfile/* @matt-kwong @jtattermusch @nicolasnoble @a11r @ctiller |
||||||
|
tools/run_tests/* @matt-kwong @jtattermusch @nicolasnoble @a11r @ctiller |
@ -0,0 +1,5 @@ |
|||||||
|
set noparent |
||||||
|
@nicolasnoble |
||||||
|
@dgquintas |
||||||
|
@ctiller |
||||||
|
|
@ -0,0 +1,2 @@ |
|||||||
|
@jtattermusch |
||||||
|
|
@ -0,0 +1,2 @@ |
|||||||
|
@ejona86 PROTOCOL-HTTP2.md interop-test-descriptions.md |
||||||
|
|
@ -0,0 +1,2 @@ |
|||||||
|
@jboeuf |
||||||
|
@nicolasnoble |
@ -0,0 +1,4 @@ |
|||||||
|
@ctiller |
||||||
|
@markdroth |
||||||
|
@dgquintas |
||||||
|
|
@ -0,0 +1,4 @@ |
|||||||
|
@ctiller |
||||||
|
@markdroth |
||||||
|
@dgquintas |
||||||
|
|
@ -0,0 +1,4 @@ |
|||||||
|
@ctiller |
||||||
|
@markdroth |
||||||
|
@dgquintas |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
@jtattermusch |
||||||
|
@apolcyn |
||||||
|
|
@ -0,0 +1,2 @@ |
|||||||
|
@murgatroid99 |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
@muxi |
||||||
|
@makdharma |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
@stanley-cheung |
||||||
|
@murgatroid99 |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
@nathanielmanistaatgoogle |
||||||
|
@kpayson64 |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
@apolcyn |
||||||
|
@murgatroid99 |
||||||
|
|
@ -0,0 +1,4 @@ |
|||||||
|
@matt-kwong |
||||||
|
@jtattermusch |
||||||
|
@nicolasnoble |
||||||
|
|
@ -0,0 +1,5 @@ |
|||||||
|
set noparent |
||||||
|
@ctiller |
||||||
|
@dgquintas |
||||||
|
@markdroth |
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
@matt-kwong |
||||||
|
@jtattermusch |
||||||
|
|
@ -0,0 +1,175 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# 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. |
||||||
|
|
||||||
|
import argparse |
||||||
|
import collections |
||||||
|
import operator |
||||||
|
import os |
||||||
|
import re |
||||||
|
import subprocess |
||||||
|
|
||||||
|
# |
||||||
|
# Find the root of the git tree |
||||||
|
# |
||||||
|
|
||||||
|
git_root = (subprocess |
||||||
|
.check_output(['git', 'rev-parse', '--show-toplevel']) |
||||||
|
.decode('utf-8') |
||||||
|
.strip()) |
||||||
|
|
||||||
|
# |
||||||
|
# Parse command line arguments |
||||||
|
# |
||||||
|
|
||||||
|
default_out = os.path.join(git_root, '.github', 'CODEOWNERS') |
||||||
|
|
||||||
|
argp = argparse.ArgumentParser('Generate .github/CODEOWNERS file') |
||||||
|
argp.add_argument('--out', '-o', |
||||||
|
type=str, |
||||||
|
default=default_out, |
||||||
|
help='Output file (default %s)' % default_out) |
||||||
|
args = argp.parse_args() |
||||||
|
|
||||||
|
# |
||||||
|
# Walk git tree to locate all OWNERS files |
||||||
|
# |
||||||
|
|
||||||
|
owners_files = [os.path.join(root, 'OWNERS') |
||||||
|
for root, dirs, files in os.walk(git_root) |
||||||
|
if 'OWNERS' in files] |
||||||
|
|
||||||
|
# |
||||||
|
# Parse owners files |
||||||
|
# |
||||||
|
|
||||||
|
Owners = collections.namedtuple('Owners', 'parent directives dir') |
||||||
|
Directive = collections.namedtuple('Directive', 'who globs') |
||||||
|
|
||||||
|
def parse_owners(filename): |
||||||
|
with open(filename) as f: |
||||||
|
src = f.read().splitlines() |
||||||
|
parent = True |
||||||
|
directives = [] |
||||||
|
for line in src: |
||||||
|
line = line.strip() |
||||||
|
# line := directive | comment |
||||||
|
if not line: continue |
||||||
|
if line[0] == '#': continue |
||||||
|
# it's a directive |
||||||
|
directive = None |
||||||
|
if line == 'set noparent': |
||||||
|
parent = False |
||||||
|
elif line == '*': |
||||||
|
directive = Directive(who='*', globs=[]) |
||||||
|
elif ' ' in line: |
||||||
|
(who, globs) = line.split(' ', 1) |
||||||
|
globs_list = [glob |
||||||
|
for glob in globs.split(' ') |
||||||
|
if glob] |
||||||
|
directive = Directive(who=who, globs=globs_list) |
||||||
|
else: |
||||||
|
directive = Directive(who=line, globs=[]) |
||||||
|
if directive: |
||||||
|
directives.append(directive) |
||||||
|
return Owners(parent=parent, |
||||||
|
directives=directives, |
||||||
|
dir=os.path.relpath(os.path.dirname(filename), git_root)) |
||||||
|
|
||||||
|
owners_data = sorted([parse_owners(filename) |
||||||
|
for filename in owners_files], |
||||||
|
key=operator.attrgetter('dir')) |
||||||
|
|
||||||
|
# |
||||||
|
# Modify owners so that parented OWNERS files point to the actual |
||||||
|
# Owners tuple with their parent field |
||||||
|
# |
||||||
|
|
||||||
|
new_owners_data = [] |
||||||
|
for owners in owners_data: |
||||||
|
if owners.parent == True: |
||||||
|
best_parent = None |
||||||
|
best_parent_score = None |
||||||
|
for possible_parent in owners_data: |
||||||
|
if possible_parent is owners: continue |
||||||
|
rel = os.path.relpath(owners.dir, possible_parent.dir) |
||||||
|
# '..' ==> we had to walk up from possible_parent to get to owners |
||||||
|
# ==> not a parent |
||||||
|
if '..' in rel: continue |
||||||
|
depth = len(rel.split(os.sep)) |
||||||
|
if not best_parent or depth < best_parent_score: |
||||||
|
best_parent = possible_parent |
||||||
|
best_parent_score = depth |
||||||
|
if best_parent: |
||||||
|
owners = owners._replace(parent = best_parent.dir) |
||||||
|
else: |
||||||
|
owners = owners._replace(parent = None) |
||||||
|
new_owners_data.append(owners) |
||||||
|
owners_data = new_owners_data |
||||||
|
|
||||||
|
# |
||||||
|
# In bottom to top order, process owners data structures to build up |
||||||
|
# a CODEOWNERS file for GitHub |
||||||
|
# |
||||||
|
|
||||||
|
def glob_intersect(g1, g2): |
||||||
|
if not g2: |
||||||
|
return all(c == '*' for c in g1) |
||||||
|
if not g1: |
||||||
|
return all(c == '*' for c in g2) |
||||||
|
c1, *t1 = g1 |
||||||
|
c2, *t2 = g2 |
||||||
|
if c1 == '*': |
||||||
|
return glob_intersect(g1, t2) or glob_intersect(t1, g2) |
||||||
|
if c2 == '*': |
||||||
|
return glob_intersect(t1, g2) or glob_intersect(g1, t2) |
||||||
|
return c1 == c2 and glob_intersect(t1, t2) |
||||||
|
|
||||||
|
def add_parent_to_globs(parent, globs): |
||||||
|
if not parent: return |
||||||
|
for owners in owners_data: |
||||||
|
if owners.dir == parent: |
||||||
|
for directive in owners.directives: |
||||||
|
for dglob in directive.globs or ['*']: |
||||||
|
for gglob, glob in globs.items(): |
||||||
|
if glob_intersect(dglob, gglob): |
||||||
|
if directive.who not in glob: |
||||||
|
glob.append(directive.who) |
||||||
|
add_parent_to_globs(owners.parent, globs) |
||||||
|
return |
||||||
|
assert(False) |
||||||
|
|
||||||
|
todo = owners_data.copy() |
||||||
|
done = set() |
||||||
|
with open(args.out, 'w') as out: |
||||||
|
out.write('# Auto-generated by the tools/mkowners/mkowners.py tool\n') |
||||||
|
out.write('# Uses OWNERS files in different modules throughout the\n') |
||||||
|
out.write('# repository as the source of truth for module ownership.\n') |
||||||
|
while todo: |
||||||
|
head, *todo = todo |
||||||
|
if head.parent and not head.parent in done: |
||||||
|
todo.append(head) |
||||||
|
continue |
||||||
|
globs = collections.OrderedDict() |
||||||
|
for directive in head.directives: |
||||||
|
for glob in directive.globs or ['*']: |
||||||
|
if glob not in globs: |
||||||
|
globs[glob] = [] |
||||||
|
globs[glob].append(directive.who) |
||||||
|
add_parent_to_globs(head.parent, globs) |
||||||
|
for glob, owners in globs.items(): |
||||||
|
out.write('%s %s\n' % ( |
||||||
|
os.path.join(head.dir, glob) if head.dir != '.' else glob, |
||||||
|
' '.join(owners))) |
||||||
|
done.add(head.dir) |
@ -0,0 +1,4 @@ |
|||||||
|
@matt-kwong |
||||||
|
@jtattermusch |
||||||
|
@nicolasnoble |
||||||
|
|
@ -1,41 +0,0 @@ |
|||||||
#!/usr/bin/env python |
|
||||||
# Copyright 2017 gRPC authors. |
|
||||||
# |
|
||||||
# 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. |
|
||||||
|
|
||||||
"""This sends out a warning if any changes to the bazel dir are made.""" |
|
||||||
|
|
||||||
from __future__ import print_function |
|
||||||
from subprocess import check_output |
|
||||||
|
|
||||||
import comment_on_pr |
|
||||||
import os |
|
||||||
|
|
||||||
_WARNING_MESSAGE = 'WARNING: You are making changes in the Bazel subdirectory. ' \ |
|
||||||
'Please get explicit approval from @nicolasnoble before merging.' |
|
||||||
|
|
||||||
|
|
||||||
def _get_changed_files(base_branch): |
|
||||||
""" |
|
||||||
Get list of changed files between current branch and base of target merge branch |
|
||||||
""" |
|
||||||
# Get file changes between branch and merge-base of specified branch |
|
||||||
base_commit = check_output(["git", "merge-base", base_branch, "HEAD"]).rstrip() |
|
||||||
return check_output(["git", "diff", base_commit, "--name-only"]).splitlines() |
|
||||||
|
|
||||||
|
|
||||||
# ghprbTargetBranch environment variable only available during a Jenkins PR tests |
|
||||||
if 'ghprbTargetBranch' in os.environ: |
|
||||||
changed_files = _get_changed_files('origin/%s' % os.environ['ghprbTargetBranch']) |
|
||||||
if any(file.startswith('bazel/') for file in changed_files): |
|
||||||
comment_on_pr.comment_on_pr(_WARNING_MESSAGE) |
|
@ -0,0 +1,29 @@ |
|||||||
|
#!/bin/sh |
||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# 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. |
||||||
|
|
||||||
|
|
||||||
|
set -e |
||||||
|
|
||||||
|
export TEST=true |
||||||
|
|
||||||
|
cd `dirname $0`/../../.. |
||||||
|
|
||||||
|
owners=.github/CODEOWNERS |
||||||
|
want_owners=`mktemp /tmp/submXXXXXX` |
||||||
|
|
||||||
|
tools/mkowners/mkowners.py -o $want_owners |
||||||
|
diff -u $owners $want_owners |
||||||
|
|
||||||
|
rm $want_owners |
Loading…
Reference in new issue