|
21 | 21 | import re |
22 | 22 | from subprocess import Popen, PIPE |
23 | 23 |
|
| 24 | +try: |
| 25 | + from jira.client import JIRA |
| 26 | + from jira.exceptions import JIRAError |
| 27 | +except ImportError: |
| 28 | + print "This tool requires the jira-python library" |
| 29 | + print "Install using 'sudo pip install jira-python'" |
| 30 | + sys.exit(-1) |
| 31 | + |
| 32 | +try: |
| 33 | + from github import Github |
| 34 | + from github import GithubException |
| 35 | +except ImportError: |
| 36 | + print "This tool requires the PyGithub library" |
| 37 | + print "Install using 'sudo pip install PyGithub'" |
| 38 | + sys.exit(-1) |
| 39 | + |
| 40 | +try: |
| 41 | + import unidecode |
| 42 | +except ImportError: |
| 43 | + print "This tool requires the unidecode library to decode obscure github usernames" |
| 44 | + print "Install using 'sudo pip install unidecode'" |
| 45 | + sys.exit(-1) |
| 46 | + |
24 | 47 | # Utility functions run git commands (written with Git 1.8.5) |
25 | 48 | def run_cmd(cmd): return Popen(cmd, stdout=PIPE).communicate()[0] |
26 | 49 | def get_author(commit_hash): |
@@ -122,3 +145,73 @@ def nice_join(str_list): |
122 | 145 | else: |
123 | 146 | return ", ".join(str_list[:-1]) + ", and " + str_list[-1] |
124 | 147 |
|
| 148 | +# Return the full name of the specified user on Github |
| 149 | +# If the user doesn't exist, return None |
| 150 | +def get_github_name(author, github_client): |
| 151 | + if github_client: |
| 152 | + try: |
| 153 | + return github_client.get_user(author).name |
| 154 | + except GithubException as e: |
| 155 | + # If this is not a "not found" exception |
| 156 | + if e.status != 404: |
| 157 | + raise e |
| 158 | + return None |
| 159 | + |
| 160 | +# Return the full name of the specified user on JIRA |
| 161 | +# If the user doesn't exist, return None |
| 162 | +def get_jira_name(author, jira_client): |
| 163 | + if jira_client: |
| 164 | + try: |
| 165 | + return jira_client.user(author).displayName |
| 166 | + except JIRAError as e: |
| 167 | + # If this is not a "not found" exception |
| 168 | + if e.status_code != 404: |
| 169 | + raise e |
| 170 | + return None |
| 171 | + |
| 172 | +# Return whether the given name is in the form <First Name><space><Last Name> |
| 173 | +def is_valid_author(author): |
| 174 | + if not author: return False |
| 175 | + author_words = len(author.split(" ")) |
| 176 | + return author_words == 2 or author_words == 3 |
| 177 | + |
| 178 | +# Capitalize the first letter of each word in the given author name |
| 179 | +def capitalize_author(author): |
| 180 | + if not author: return None |
| 181 | + words = author.split(" ") |
| 182 | + words = [w[0].capitalize() + w[1:] for w in words if w] |
| 183 | + return " ".join(words) |
| 184 | + |
| 185 | +# Maintain a mapping of translated author names as a cache |
| 186 | +translated_authors = {} |
| 187 | + |
| 188 | +# Format the given author in a format appropriate for the contributors list. |
| 189 | +# If the author is not an actual name, search github and JIRA for potential |
| 190 | +# replacements and log all candidates as a warning. |
| 191 | +def translate_author(github_author, github_client, jira_client, warnings): |
| 192 | + if is_valid_author(github_author): |
| 193 | + return capitalize_author(github_author) |
| 194 | + # If the translated author is already cached, just return it |
| 195 | + if github_author in translated_authors: |
| 196 | + return translated_authors[github_author] |
| 197 | + # Otherwise, author name is not found, so we need to search for an alternative name |
| 198 | + candidates = set() |
| 199 | + github_name = get_github_name(github_author, github_client) |
| 200 | + jira_name = get_jira_name(github_author, jira_client) |
| 201 | + if is_valid_author(github_name): github_name = capitalize_author(github_name) |
| 202 | + if is_valid_author(jira_name): jira_name = capitalize_author(jira_name) |
| 203 | + if github_name: candidates.add(github_name) |
| 204 | + if jira_name: candidates.add(jira_name) |
| 205 | + # Only use the github name as a replacement automatically |
| 206 | + # The JIRA name may not make sense because it can belong to someone else |
| 207 | + if is_valid_author(github_name): |
| 208 | + candidates_message = " (another candidate is %s)" % jira_name if jira_name else "" |
| 209 | + warnings.append("Replacing github user %s with %s%s" % (github_author, github_name, candidates_message)) |
| 210 | + translated_authors[github_name] = github_name |
| 211 | + return translated_authors[github_name] |
| 212 | + # No direct replacement, so return the original author and list any candidates found |
| 213 | + candidates_message = " (candidates: %s)" % nice_join(candidates) if candidates else "" |
| 214 | + warnings.append("Unable to find a replacement for github user %s%s" % (github_author, candidates_message)) |
| 215 | + translated_authors[github_author] = github_author |
| 216 | + return translated_authors[github_author] |
| 217 | + |
0 commit comments