123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- #!/usr/bin/env python3
- import collections
- import json
- import pathlib
- import subprocess
- import sys
- DEFAULT_REF = 'origin/master'
- THE_BIG_LIST_OF_NAUGHTY_FILES = list(map(pathlib.Path, [
- #
- # Problems with files listed here get lighter treatment: they are blocking
- # only when they are a part of the current pull request.
- #
- # for pylint
- 'Documentation/conf.py',
- 'LibOS/shim/test/apps/ltp/contrib/conf_lint.py',
- 'LibOS/shim/test/apps/ltp/contrib/conf_merge.py',
- 'LibOS/shim/test/apps/ltp/contrib/conf_missing.py',
- 'LibOS/shim/test/apps/ltp/contrib/conf_remove_must_pass.py',
- 'LibOS/shim/test/apps/ltp/contrib/has_own_main.py',
- 'LibOS/shim/test/apps/ltp/contrib/report.py',
- 'LibOS/shim/test/apps/ltp/runltp_xml.py',
- 'LibOS/shim/test/apps/python-scipy-insecure/scripts/test-numpy.py',
- 'LibOS/shim/test/apps/python-scipy-insecure/scripts/test-scipy.py',
- 'LibOS/shim/test/apps/python-simple/scripts/benchrun.py',
- 'LibOS/shim/test/apps/python-simple/scripts/dummy-web-server.py',
- 'LibOS/shim/test/apps/python-simple/scripts/fibonacci.py',
- 'LibOS/shim/test/apps/python-simple/scripts/helloworld.py',
- 'LibOS/shim/test/apps/python-simple/scripts/test-http.py',
- 'LibOS/shim/test/fs/test_fs.py',
- 'LibOS/shim/test/regression/test_libos.py',
- 'Pal/regression/test_pal.py',
- 'Pal/src/host/Linux-SGX/sgx-driver/link-intel-driver.py',
- 'Pal/src/host/Linux/pal-gdb.py',
- 'Scripts/regression.py',
- 'Tools',
- # for shellcheck
- 'LibOS/shim/test/apps/bash/scripts/bash_test.sh',
- 'LibOS/shim/test/apps/common_tools/benchmark-http.sh',
- 'LibOS/shim/test/apps/python-simple/run-tests.sh',
- 'LibOS/shim/test/native',
- 'Pal/src/host/Linux-SGX/debugger/gdb',
- 'Scripts/list-all-graphene.sh',
- 'Scripts/memusg',
- '.ci/run-pylint',
- '.ci/run-shellcheck',
- ]))
- def get_diff_ranges(ref=DEFAULT_REF):
- '''Get chunks affected by a merge request
- Args:
- ref (str): a reference to diff the HEAD against (default: origin/master)
- Returns:
- dict: a dict with filenames in keys and list of `(start, end)` ranges in
- values (start is inclusive, end is not, wrt :py:func:`range`)
- '''
- files = collections.defaultdict(list)
- data = subprocess.check_output(['git', 'diff', '-U0', ref, 'HEAD']).decode()
- path = None
- for line in data.split('\n'):
- if line.startswith('+++ '):
- path = (None if line == '+++ /dev/null'
- else line.split('/', maxsplit=1)[-1])
- continue
- if line.startswith('@@ '):
- # @@ -8,0 +9 @@ [class name or previous line or whatever]
- if path is None: # /dev/null
- continue
- _, _, plus, *_ = line.split()
- start, length, *_ = *(int(i) for i in plus[1:].split(',')), 1
- if not length:
- # remove-only chunk
- continue
- files[path].append((start, start + length))
- return files
- class Diff:
- '''A quick and dirty diff evaluator
- >>> diff = Diff()
- >>> (message['file'], message['line']) in diff
- True # or False
- >>> diff.message_is_important(message)
- True # or False
- The default diff is to the ``origin/master`` ref.
- '''
- # pylint: disable=too-few-public-methods
- def __init__(self, ref=DEFAULT_REF):
- self._files = get_diff_ranges(ref)
- def __contains__(self, pathline):
- path, line = pathline
- try:
- return any(start <= line < end for start, end in self._files[path])
- except KeyError:
- return False
- def message_is_important(self, message):
- path = pathlib.Path(message['path'])
- for i in THE_BIG_LIST_OF_NAUGHTY_FILES:
- try:
- path.relative_to(i)
- break
- except ValueError:
- # path is not .relative_to() the path from WHITELIST
- pass
- else:
- # not on whitelist: always complain
- return True
- if (message['path'], message['line']) in self:
- # on whitelist, but in diff: do complain
- return True
- # on whitelist and outside diff: don't complain
- return False
- def main():
- diff = Diff()
- with sys.stdin:
- pylint = json.load(sys.stdin)
- ret = 0
- for message in pylint:
- # shellcheck
- if 'path' not in message:
- message['path'] = message['file']
- if 'symbol' not in message:
- message['symbol'] = message['code']
- if diff.message_is_important(message):
- if not ret:
- print('MESSAGES AFFECTING THIS PR:')
- print('{path} +{line}:{column}: {symbol}: {message}'.format(
- **message))
- ret += 1
- return min(ret, 255)
- if __name__ == '__main__':
- sys.exit(main())
|