diff options
author | bst-marge-bot <marge-bot@buildstream.build> | 2019-07-31 17:13:06 +0000 |
---|---|---|
committer | bst-marge-bot <marge-bot@buildstream.build> | 2019-07-31 17:13:06 +0000 |
commit | 3d224253b3448517f5bd36e68e9ff6ac205a0ca9 (patch) | |
tree | eb9860d5c4ee00450b989f350531b95e28588d48 | |
parent | 78a48653ea9c0701e4a6a774af49a1d35df8135a (diff) | |
parent | 702f10c0fa6b6be233f83ea97fad73ec8eca8665 (diff) | |
download | buildstream-3d224253b3448517f5bd36e68e9ff6ac205a0ca9.tar.gz |
Merge branch 'alexfazakas/fetch-committers' into 'master'
Automatically build a list of committers
Closes #1071
See merge request BuildStream/buildstream!1505
-rw-r--r-- | CONTRIBUTING.rst | 49 | ||||
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | contrib/COMMITTERS.rst.j2 | 18 | ||||
-rwxr-xr-x | contrib/update_committers.py | 111 |
4 files changed, 178 insertions, 7 deletions
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index b128c7f9b..11b8d9192 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -200,6 +200,55 @@ separately. This is a part of #123 +Committer access +---------------- + +Committers in the BuildStream project are those folks to whom the right to +directly commit changes to our version controlled resources has been granted. +While every contribution is +valued regardless of its source, not every person who contributes code to the +project will earn commit access. The `COMMITTERS`_ file lists all committers. + +Whenever someone is granted (or revoked) commit access, an Owner or Maintainer +should run the the script located at `contrib/update_committers.py` with their +personal access token, updating the COMMITTERS.rst list and opening an MR +with their changes. + +.. _COMMITTERS: https://gitlab.com/BuildStream/buildstream/blob/master/COMMITTERS.rst + + +How commit access is granted +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After someone has successfully contributed a few non-trivial patches, some full +committer, usually whoever has reviewed and applied the most patches from that +contributor, proposes them for commit access. This proposal is sent only to the +other full committers - the ensuing discussion is private, so that everyone can +feel comfortable speaking their minds. Assuming there are no objections, the +contributor is granted commit access. The decision is made by consensus; there +are no formal rules governing the procedure, though generally if someone strongly +objects the access is not offered, or is offered on a provisional basis. + +This of course relies on contributors being responsive and showing willingness +to address any problems that may arise after landing patches. However, the primary +criterion for commit access is good judgement. + +You do not have to be a technical wizard or demonstrate deep knowledge of the +entire codebase to become a committer. You just need to know what you don't +know. Non-code contributions are just as valuable in the path to commit access. +If your patches adhere to the guidelines in this file, adhere to all the usual +unquantifiable rules of coding (code should be readable, robust, maintainable, etc.), +and respect the Hippocratic Principle of "first, do no harm", then you will probably +get commit access pretty quickly. The size, complexity, and quantity of your patches +do not matter as much as the degree of care you show in avoiding bugs and minimizing +unnecessary impact on the rest of the code. Many full committers are people who have +not made major code contributions, but rather lots of small, clean fixes, each of +which was an unambiguous improvement to the code. (Of course, this does not mean the +project needs a bunch of very trivial patches whose only purpose is to gain commit +access; knowing what's worth a patch post and what's not is part of showing good +judgement.) + + Coding guidelines ----------------- This section discusses coding style and other guidelines for hacking diff --git a/MAINTAINERS b/MAINTAINERS deleted file mode 100644 index f9d27bb29..000000000 --- a/MAINTAINERS +++ /dev/null @@ -1,7 +0,0 @@ -Tristan Van Berkom -E-mail: tristan.vanberkom@codethink.co.uk -Userid: tvb - -Jürg Billeter -E-mail: juerg.billeter@codethink.co.uk -Userid: juergbi diff --git a/contrib/COMMITTERS.rst.j2 b/contrib/COMMITTERS.rst.j2 new file mode 100644 index 000000000..6f602d6c3 --- /dev/null +++ b/contrib/COMMITTERS.rst.j2 @@ -0,0 +1,18 @@ +.. _committers: + +Committers +========== + +Full commit access +------------------- +List of people with full commit access, i.e. blanket commit access to +the BuildStream codebase. Note that this is not a full list of all +contributors. + ++-----------------------------------+-----------------------------------+ +| Full Name | GitLab User | ++===================================+===================================+ +{% for name, username in committers.items() -%} +| {{ get_table_entry(name) }}| {{ get_table_entry(username)}}| ++-----------------------------------+-----------------------------------+ +{% endfor %} diff --git a/contrib/update_committers.py b/contrib/update_committers.py new file mode 100755 index 000000000..f0faac327 --- /dev/null +++ b/contrib/update_committers.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +"""A script to set up COMMITTERS.rst according to gitlab committers.""" + +import os +import subprocess +import argparse +import json +import urllib.request +import urllib.parse +from jinja2 import Environment, FileSystemLoader +from collections import OrderedDict + +GIT_ERROR = 1 +MERGE_REQUEST = 'https://gitlab.com/api/v4/projects/1975139/merge_requests' +ALL_MEMBERS = 'https://gitlab.com/api/v4/projects/1975139/members/all' +PROTECTED = 'https://gitlab.com/api/v4/projects/1975139/protected_branches/master' +USERS = 'https://gitlab.com/api/v4/users/{}' +MAX_LEN = len('Full Name ') + + +def get_committers(token: str) -> OrderedDict: + request = urllib.request.Request(PROTECTED) + request.add_header('PRIVATE-TOKEN', token) + response = urllib.request.urlopen(request).read().decode('utf-8') + named_developers = [x['user_id'] for x in json.loads(response)['merge_access_levels']] + request = urllib.request.Request(ALL_MEMBERS) + request.add_header('PRIVATE-TOKEN', token) + all_members = json.loads(urllib.request.urlopen(request).read().decode('utf-8')) + names_usernames_dictionary = OrderedDict() + for contributor in all_members: + if contributor['access_level'] >= 40: + names_usernames_dictionary[contributor['name']] = contributor['username'] + for contributor in named_developers: + if contributor: + request = urllib.request.Request(USERS.format(contributor)) + response = json.loads(urllib.request.urlopen(request).read().decode('utf-8')) + if response['name'] != 'bst-marge-bot': + names_usernames_dictionary[response['name']] = response['username'] + return names_usernames_dictionary + + +def get_table_entry(entry: str) -> str: + res = entry + for _ in range(MAX_LEN - len(entry)): + res = res + ' ' + return res + + +def find_repository_root() -> str: + root = os.getcwd() + try: + root = subprocess.check_output('git rev-parse --show-toplevel', shell=True) + except CalledProcessError as e: + print('The current working directory is not a git repository. \ + \"git rev-parse --show-toplevel\" exited with code {}.'.format(e.returncode)) + sys.exit(GIT_ERROR) + return root.rstrip().decode('utf-8') + + +def create_committers_file(committers: OrderedDict): + contrib_directory = os.path.join(find_repository_root(), 'contrib') + file_loader = FileSystemLoader(contrib_directory) + env = Environment(loader=file_loader) + template = env.get_template('COMITTERS.rst.j2') + render_output = template.render(committers=committers, get_table_entry=get_table_entry) + committers_file = os.path.join(contrib_directory, 'COMMITTERS.rst') + + with open(committers_file, 'w') as f: + f.write(render_output) + + +def commit_changes_if_needed(token: str): + committers_file = os.path.join(find_repository_root(), 'contrib/COMMITTERS.rst') + git_diff = subprocess.call('git diff --quiet {}'.format(committers_file), shell=True) + if git_diff: + commit_message = '\'contrib: Update COMMITTERS.rst\'' + branch_name = 'update_committers' + subprocess.call('git add {}'.format(committers_file), shell=True) + subprocess.call('git commit -m {}'.format(commit_message), shell=True) + try: + subprocess.call('git push -u origin {} 2>&1'.format(branch_name), + shell=True) + except CalledProcessError as e: + print('Could not push to remote branch. \"git push -u origin {}\" \ + exited with code {}.'.format(branch_name, e.returncode)) + sys.exit(GIT_ERROR) + data = urllib.parse.urlencode({'source_branch': 'update_committers', + 'target_branch': 'master', + 'title': 'Update COMMITTERS.rst file'}) + request = urllib.request.Request(MERGE_REQUEST, data=bytearray(data, 'ASCII')) + request.add_header('PRIVATE-TOKEN', token) + response = urllib.request.urlopen(request).read().decode('utf-8') + + +def main(): + parser = argparse.ArgumentParser( + description="Update gitlab committers according to COMMITTERS.rst" + ) + parser.add_argument( + "token", type=str, + help="Your private access token. See https://gitlab.com/profile/personal_access_tokens." + ) + args = parser.parse_args() + + committers = get_committers(args.token) + create_committers_file(committers) + commit_changes_if_needed(args.token) + + +if __name__ == '__main__': + main() |