|
7 | 7 | ## It is set as callback for `src/ci/docker/x86_64-gnu-tools/repo.sh` by the CI scripts
|
8 | 8 | ## when a new commit lands on `master` (i.e., after it passed all checks on `auto`).
|
9 | 9 |
|
| 10 | +from __future__ import print_function |
| 11 | + |
10 | 12 | import sys
|
11 | 13 | import re
|
12 | 14 | import os
|
|
20 | 22 | import urllib.request as urllib2
|
21 | 23 |
|
22 | 24 | # List of people to ping when the status of a tool or a book changed.
|
| 25 | +# These should be collaborators of the rust-lang/rust repository (with at least |
| 26 | +# read privileges on it). CI will fail otherwise. |
23 | 27 | MAINTAINERS = {
|
24 | 28 | 'miri': '@oli-obk @RalfJung @eddyb',
|
25 | 29 | 'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch @flip1995 @yaahc',
|
|
52 | 56 | }
|
53 | 57 |
|
54 | 58 |
|
| 59 | +def validate_maintainers(repo, github_token): |
| 60 | + '''Ensure all maintainers are assignable on a GitHub repo''' |
| 61 | + next_link_re = re.compile(r'<([^>]+)>; rel="next"') |
| 62 | + |
| 63 | + # Load the list of assignable people in the GitHub repo |
| 64 | + assignable = [] |
| 65 | + url = 'https://api.github.com/repos/%s/collaborators?per_page=100' % repo |
| 66 | + while url is not None: |
| 67 | + response = urllib2.urlopen(urllib2.Request(url, headers={ |
| 68 | + 'Authorization': 'token ' + github_token, |
| 69 | + # Properly load nested teams. |
| 70 | + 'Accept': 'application/vnd.github.hellcat-preview+json', |
| 71 | + })) |
| 72 | + for user in json.loads(response.read()): |
| 73 | + assignable.append(user['login']) |
| 74 | + # Load the next page if available |
| 75 | + if 'Link' in response.headers: |
| 76 | + matches = next_link_re.match(response.headers['Link']) |
| 77 | + if matches is not None: |
| 78 | + url = matches.group(1) |
| 79 | + else: |
| 80 | + url = None |
| 81 | + |
| 82 | + errors = False |
| 83 | + for tool, maintainers in MAINTAINERS.items(): |
| 84 | + for maintainer in maintainers.split(' '): |
| 85 | + if maintainer.startswith('@'): |
| 86 | + maintainer = maintainer[1:] |
| 87 | + if maintainer not in assignable: |
| 88 | + errors = True |
| 89 | + print( |
| 90 | + "error: %s maintainer @%s is not assignable in the %s repo" |
| 91 | + % (tool, maintainer, repo), |
| 92 | + ) |
| 93 | + |
| 94 | + if errors: |
| 95 | + print() |
| 96 | + print(" To be assignable, a person needs to be explicitly listed as a") |
| 97 | + print(" collaborator in the repository settings. The simple way to") |
| 98 | + print(" fix this is to ask someone with 'admin' privileges on the repo") |
| 99 | + print(" to add the person or whole team as a collaborator with 'read'") |
| 100 | + print(" privileges. Those privileges don't grant any extra permissions") |
| 101 | + print(" so it's safe to apply them.") |
| 102 | + print() |
| 103 | + print("The build will fail due to this.") |
| 104 | + exit(1) |
| 105 | + |
55 | 106 | def read_current_status(current_commit, path):
|
56 | 107 | '''Reads build status of `current_commit` from content of `history/*.tsv`
|
57 | 108 | '''
|
@@ -200,6 +251,15 @@ def update_latest(
|
200 | 251 |
|
201 | 252 |
|
202 | 253 | if __name__ == '__main__':
|
| 254 | + if 'TOOLSTATE_VALIDATE_MAINTAINERS_REPO' in os.environ: |
| 255 | + repo = os.environ['TOOLSTATE_VALIDATE_MAINTAINERS_REPO'] |
| 256 | + if 'TOOLSTATE_REPO_ACCESS_TOKEN' in os.environ: |
| 257 | + github_token = os.environ['TOOLSTATE_REPO_ACCESS_TOKEN'] |
| 258 | + validate_maintainers(repo, github_token) |
| 259 | + else: |
| 260 | + print('skipping toolstate maintainers validation since no GitHub token is present') |
| 261 | + exit(0) |
| 262 | + |
203 | 263 | cur_commit = sys.argv[1]
|
204 | 264 | cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
|
205 | 265 | cur_commit_msg = sys.argv[2]
|
|
0 commit comments