|
12 | 12 |
|
13 | 13 | SRCDIR = sysconfig.get_config_var('srcdir')
|
14 | 14 |
|
15 |
| - |
16 | 15 | def n_files_str(count):
|
17 | 16 | """Return 'N file(s)' with the proper plurality on 'file'."""
|
18 | 17 | return "{} file{}".format(count, "s" if count != 1 else "")
|
@@ -50,32 +49,86 @@ def mq_patches_applied():
|
50 | 49 | st.stderr.close()
|
51 | 50 |
|
52 | 51 |
|
| 52 | +def get_git_branch(): |
| 53 | + """Get the symbolic name for the current git branch""" |
| 54 | + cmd = "git rev-parse --abbrev-ref HEAD".split() |
| 55 | + try: |
| 56 | + return subprocess.check_output(cmd, stderr=subprocess.PIPE) |
| 57 | + except subprocess.CalledProcessError: |
| 58 | + return None |
| 59 | + |
| 60 | + |
| 61 | +def get_git_upstream_remote(): |
| 62 | + """Get the remote name to use for upstream branches |
| 63 | +
|
| 64 | + Uses "upstream" if it exists, "origin" otherwise |
| 65 | + """ |
| 66 | + cmd = "git remote get-url upstream".split() |
| 67 | + try: |
| 68 | + subprocess.check_output(cmd, stderr=subprocess.PIPE) |
| 69 | + except subprocess.CalledProcessError: |
| 70 | + return "origin" |
| 71 | + return "upstream" |
| 72 | + |
| 73 | + |
| 74 | +@status("Getting base branch for PR", |
| 75 | + info=lambda x: x if x is not None else "not a PR branch") |
| 76 | +def get_base_branch(): |
| 77 | + if not os.path.isdir(os.path.join(SRCDIR, '.git')): |
| 78 | + # Not a git checkout, so there's no base branch |
| 79 | + return None |
| 80 | + version = sys.version_info |
| 81 | + if version.releaselevel == 'alpha': |
| 82 | + base_branch = "master" |
| 83 | + else: |
| 84 | + base_branch = "{0.major}.{0.minor}".format(version) |
| 85 | + this_branch = get_git_branch() |
| 86 | + if this_branch is None or this_branch == base_branch: |
| 87 | + # Not on a git PR branch, so there's no base branch |
| 88 | + return None |
| 89 | + upstream_remote = get_git_upstream_remote() |
| 90 | + return upstream_remote + "/" + base_branch |
| 91 | + |
| 92 | + |
53 | 93 | @status("Getting the list of files that have been added/changed",
|
54 | 94 | info=lambda x: n_files_str(len(x)))
|
55 |
| -def changed_files(): |
56 |
| - """Get the list of changed or added files from the VCS.""" |
| 95 | +def changed_files(base_branch=None): |
| 96 | + """Get the list of changed or added files from Mercurial or git.""" |
57 | 97 | if os.path.isdir(os.path.join(SRCDIR, '.hg')):
|
58 |
| - vcs = 'hg' |
| 98 | + if base_branch is not None: |
| 99 | + sys.exit('need a git checkout to check PR status') |
59 | 100 | cmd = 'hg status --added --modified --no-status'
|
60 | 101 | if mq_patches_applied():
|
61 | 102 | cmd += ' --rev qparent'
|
62 |
| - elif os.path.isdir('.svn'): |
63 |
| - vcs = 'svn' |
64 |
| - cmd = 'svn status --quiet --non-interactive --ignore-externals' |
65 |
| - else: |
66 |
| - sys.exit('need a checkout to get modified files') |
67 |
| - |
68 |
| - st = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) |
69 |
| - try: |
70 |
| - st.wait() |
71 |
| - if vcs == 'hg': |
| 103 | + st = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) |
| 104 | + try: |
72 | 105 | return [x.decode().rstrip() for x in st.stdout]
|
| 106 | + finally: |
| 107 | + st.stdout.close() |
| 108 | + elif os.path.isdir(os.path.join(SRCDIR, '.git')): |
| 109 | + if base_branch: |
| 110 | + cmd = 'git diff --name-status ' + base_branch |
73 | 111 | else:
|
74 |
| - output = (x.decode().rstrip().rsplit(None, 1)[-1] |
75 |
| - for x in st.stdout if x[0] in 'AM') |
76 |
| - return set(path for path in output if os.path.isfile(path)) |
77 |
| - finally: |
78 |
| - st.stdout.close() |
| 112 | + cmd = 'git status --porcelain' |
| 113 | + filenames = [] |
| 114 | + st = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) |
| 115 | + try: |
| 116 | + for line in st.stdout: |
| 117 | + line = line.decode().rstrip() |
| 118 | + status_text, filename = line.split(None, 1) |
| 119 | + status = set(status_text) |
| 120 | + # modified, added or unmerged files |
| 121 | + if not status.intersection('MAU'): |
| 122 | + continue |
| 123 | + if ' -> ' in filename: |
| 124 | + # file is renamed |
| 125 | + filename = filename.split(' -> ', 2)[1].strip() |
| 126 | + filenames.append(filename) |
| 127 | + finally: |
| 128 | + st.stdout.close() |
| 129 | + return filenames |
| 130 | + else: |
| 131 | + sys.exit('need a checkout to get modified files') |
79 | 132 |
|
80 | 133 |
|
81 | 134 | def report_modified_files(file_paths):
|
@@ -154,7 +207,8 @@ def reported_news(file_paths):
|
154 | 207 |
|
155 | 208 |
|
156 | 209 | def main():
|
157 |
| - file_paths = changed_files() |
| 210 | + base_branch = get_base_branch() |
| 211 | + file_paths = changed_files(base_branch) |
158 | 212 | python_files = [fn for fn in file_paths if fn.endswith('.py')]
|
159 | 213 | c_files = [fn for fn in file_paths if fn.endswith(('.c', '.h'))]
|
160 | 214 | doc_files = [fn for fn in file_paths if fn.startswith('Doc') and
|
|
0 commit comments