forked from scipy/scipy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lint.py
executable file
·114 lines (88 loc) · 2.89 KB
/
lint.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env python
import os
import sys
import subprocess
from argparse import ArgumentParser
CONFIG = os.path.join(
os.path.abspath(os.path.dirname(__file__)),
'lint_diff.ini',
)
def rev_list(branch, num_commits):
"""List commits in reverse chronological order.
Only the first `num_commits` are shown.
"""
res = subprocess.run(
[
'git',
'rev-list',
'--max-count',
f'{num_commits}',
'--first-parent',
branch
],
stdout=subprocess.PIPE,
encoding='utf-8',
)
res.check_returncode()
return res.stdout.rstrip('\n').split('\n')
def find_branch_point(branch):
"""Find when the current branch split off from the given branch.
It is based off of this Stackoverflow post:
https://stackoverflow.com/questions/1527234/finding-a-branch-point-with-git#4991675
"""
branch_commits = rev_list('HEAD', 1000)
main_commits = set(rev_list(branch, 1000))
for branch_commit in branch_commits:
if branch_commit in main_commits:
return branch_commit
# If a branch split off over 1000 commits ago we will fail to find
# the ancestor.
raise RuntimeError(
'Failed to find a common ancestor in the last 1000 commits'
)
def diff_files(sha):
"""Find the diff since the given SHA."""
res = subprocess.run(
['git', 'diff', '--name-only', '-z', sha, '--', '*.py'],
stdout=subprocess.PIPE,
encoding='utf-8'
)
res.check_returncode()
return [f for f in res.stdout.split('\0') if f]
def run_flake8(files):
if not files:
return 0, ""
res = subprocess.run(
['flake8', '--config', CONFIG] + files,
stdout=subprocess.PIPE,
encoding='utf-8'
)
return res.returncode, res.stdout
def main():
parser = ArgumentParser()
# In Python 3.9, can use: argparse.BooleanOptionalAction
parser.add_argument("--diff-against", dest='branch',
type=str, default=None,
help="Diff against "
"this branch and lint modified files. Use either "
"`--diff-against` or `--files`, but not both.")
parser.add_argument("--files", nargs='*',
help="Lint these files or directories; "
"use **/*.py to lint all files")
args = parser.parse_args()
if not ((args.files is None) ^ (args.branch is None)):
print('Specify either `--diff-against` or `--files`. Aborting.')
sys.exit(1)
if args.branch:
branch_point = find_branch_point(args.branch)
files = diff_files(branch_point)
else:
files = args.files
rc, errors = run_flake8(files)
if errors:
print(errors)
else:
print("No linting errors found.")
sys.exit(rc)
if __name__ == '__main__':
main()