##// END OF EJS Templates
contrib: add a partial-merge tool for sorted lists (such as Python imports)...
contrib: add a partial-merge tool for sorted lists (such as Python imports) This is a pretty naive tool that uses a regular expression for matching lines. It is based on a Google-internal tool that worked in a similar way. For now, the regular expression is hard-coded to attempt to match single-line Python imports. The only commit I've found in the hg core repo where the tool helped was commit 9cd6292abfdf. I think that's because we often use multiple imports per import statement. I think this tool is still a decent first step (especially once the regex is made configurable in the next patch). The merging should ideally use a proper Python parser and do the merge at the AST (or CST?) level, but that's significantly harder, especially if you want to preserve comments and whitespace. It's also less generic. Differential Revision: https://phab.mercurial-scm.org/D12380

File last commit:

r49730:6000f5b2 default
r49874:681b25ea default
Show More
python3-ratchet.py
161 lines | 4.5 KiB | text/x-python | PythonLexer
/ contrib / python3-ratchet.py
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 # Copyright 2012 Facebook
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""Find tests that newly pass under Python 3.
The approach is simple: we maintain a whitelist of Python 3 passing
tests in the repository, and periodically run all the /other/ tests
and look for new passes. Any newly passing tests get automatically
added to the whitelist.
You probably want to run it like this:
$ cd tests
$ python3 ../contrib/python3-ratchet.py \
> --working-tests=../contrib/python3-whitelist
"""
import argparse
import json
import os
import subprocess
import sys
_hgenv = dict(os.environ)
Augie Fackler
formatting: blacken the codebase...
r43346 _hgenv.update(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 {
'HGPLAIN': '1',
}
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855
_HG_FIRST_CHANGE = '9117c6561b0bd7792fa13b50d28239d51b78e51f'
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 def _runhg(*args):
return subprocess.check_output(args, env=_hgenv)
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 def _is_hg_repo(path):
Augie Fackler
formatting: blacken the codebase...
r43346 return (
_runhg('hg', 'log', '-R', path, '-r0', '--template={node}').strip()
== _HG_FIRST_CHANGE
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855
def _py3default():
if sys.version_info[0] >= 3:
return sys.executable
return 'python3'
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 def main(argv=()):
p = argparse.ArgumentParser()
Augie Fackler
formatting: blacken the codebase...
r43346 p.add_argument(
'--working-tests', help='List of tests that already work in Python 3.'
)
p.add_argument(
'--commit-to-repo',
help='If set, commit newly fixed tests to the given repo',
)
p.add_argument(
'-j',
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 default=os.sysconf('SC_NPROCESSORS_ONLN'),
Augie Fackler
formatting: blacken the codebase...
r43346 type=int,
help='Number of parallel tests to run.',
)
p.add_argument(
'--python3',
default=_py3default(),
help='python3 interpreter to use for test run',
)
p.add_argument(
'--commit-user',
default='python3-ratchet@mercurial-scm.org',
help='Username to specify when committing to a repo.',
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 opts = p.parse_args(argv)
if opts.commit_to_repo:
if not _is_hg_repo(opts.commit_to_repo):
print('abort: specified repository is not the hg repository')
sys.exit(1)
if not opts.working_tests or not os.path.isfile(opts.working_tests):
Augie Fackler
formatting: blacken the codebase...
r43346 print(
'abort: --working-tests must exist and be a file (got %r)'
% opts.working_tests
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 sys.exit(1)
elif opts.commit_to_repo:
root = _runhg('hg', 'root').strip()
if not opts.working_tests.startswith(root):
Augie Fackler
formatting: blacken the codebase...
r43346 print(
'abort: if --commit-to-repo is given, '
'--working-tests must be from that repo'
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 sys.exit(1)
try:
Augie Fackler
formatting: blacken the codebase...
r43346 subprocess.check_call(
[
opts.python3,
'-c',
'import sys ; '
'assert ((3, 5) <= sys.version_info < (3, 6) '
'or sys.version_info >= (3, 6, 2))',
]
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 except subprocess.CalledProcessError:
Augie Fackler
formatting: blacken the codebase...
r43346 print(
'warning: Python 3.6.0 and 3.6.1 have '
'a bug which breaks Mercurial'
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 print('(see https://bugs.python.org/issue29714 for details)')
Kevin Bullock
py3: bail on ratcheting tests forward on 3.6.0 and 3.6.1
r36607 sys.exit(1)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855
Augie Fackler
formatting: blacken the codebase...
r43346 rt = subprocess.Popen(
[
opts.python3,
'run-tests.py',
'-j',
str(opts.j),
'--blacklist',
opts.working_tests,
'--json',
]
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 rt.wait()
with open('report.json') as f:
data = f.read()
report = json.loads(data.split('=', 1)[1])
newpass = set()
for test, result in report.items():
if result['result'] != 'success':
continue
# A new passing test! Huzzah!
newpass.add(test)
if newpass:
# We already validated the repo, so we can just dive right in
# and commit.
if opts.commit_to_repo:
print(len(newpass), 'new passing tests on Python 3!')
with open(opts.working_tests) as f:
oldpass = {l for l in f.read().splitlines() if l}
with open(opts.working_tests, 'w') as f:
for p in sorted(oldpass | newpass):
f.write('%s\n' % p)
Augie Fackler
formatting: blacken the codebase...
r43346 _runhg(
'hg',
'commit',
'-R',
opts.commit_to_repo,
'--user',
opts.commit_user,
'--message',
'python3: expand list of passing tests',
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 else:
print('Newly passing tests:', '\n'.join(sorted(newpass)))
sys.exit(2)
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 if __name__ == '__main__':
main(sys.argv[1:])