| Index: appengine/findit/common/repo_util.py
|
| diff --git a/appengine/findit/common/repo_util.py b/appengine/findit/common/repo_util.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9b514ea43c1827840534d0400b92f95dc471dbc0
|
| --- /dev/null
|
| +++ b/appengine/findit/common/repo_util.py
|
| @@ -0,0 +1,87 @@
|
| +# Copyright 2016 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +import json
|
| +import re
|
| +import urllib2
|
| +
|
| +CODE_REVIEW_URL_PATTERN = re.compile(
|
| + '^(?:Review URL|Review-Url): (.*\d+).*$', re.IGNORECASE)
|
| +COMMIT_POSITION_PATTERN = re.compile(
|
| + '^Cr-Commit-Position: refs/heads/master@{#(\d+)}$', re.IGNORECASE)
|
| +REVERTED_REVISION_PATTERN = re.compile(
|
| + '^> Committed: https://.+/([0-9a-fA-F]{40})$', re.IGNORECASE)
|
| +COMMIT_POSITION_CODE_REVIEW_URL_PARSING_START_LINE = -5
|
| +
|
| +
|
| +def ExtractCommitPositionAndCodeReviewUrl(message):
|
| + """Returns the commit position and code review url in the commit message.
|
| +
|
| + A "commit position" is something similar to SVN version ids; i.e.,
|
| + numeric identifiers which are issued in sequential order. The reason
|
| + we care about them is that they're easier for humans to read than
|
| + the hashes that Git uses internally for identifying commits. We
|
| + should never actually use them for *identifying* commits; they're
|
| + only for pretty printing to humans.
|
| +
|
| + Returns:
|
| + (commit_position, code_review_url)
|
| + """
|
| + if not message:
|
| + return (None, None)
|
| +
|
| + commit_position = None
|
| + code_review_url = None
|
| +
|
| + # Commit position and code review url are in the last 5 lines.
|
| + lines = message.strip().split('\n')[
|
| + COMMIT_POSITION_CODE_REVIEW_URL_PARSING_START_LINE:]
|
| + lines.reverse()
|
| +
|
| + for line in lines:
|
| + if commit_position is None:
|
| + match = COMMIT_POSITION_PATTERN.match(line)
|
| + if match:
|
| + commit_position = int(match.group(1))
|
| +
|
| + if code_review_url is None:
|
| + match = CODE_REVIEW_URL_PATTERN.match(line)
|
| + if match:
|
| + code_review_url = match.group(1)
|
| + return (commit_position, code_review_url)
|
| +
|
| +
|
| +def NormalizeEmail(email):
|
| + """Normalizes the email from git repo.
|
| +
|
| + Some email is like: test@chromium.org@bbb929c8-8fbe-4397-9dbb-9b2b20218538.
|
| + """
|
| + parts = email.split('@')
|
| + return '@'.join(parts[0:2])
|
| +
|
| +
|
| +def GetRevertedRevision(message):
|
| + """Parse message to get the reverted revision if there is one."""
|
| + lines = message.strip().splitlines()
|
| + if not lines[0].lower().startswith('revert'):
|
| + return None
|
| +
|
| + for line in reversed(lines): # pragma: no cover
|
| + # TODO: Handle cases where no reverted_revision in reverting message.
|
| + reverted_revision_match = REVERTED_REVISION_PATTERN.match(line)
|
| + if reverted_revision_match:
|
| + return reverted_revision_match.group(1)
|
| +
|
| +
|
| +def GetRepoToCloneUrlDict(host_url):
|
| + # Gerrit prepends )]}' to json-formatted response.
|
| + content = urllib2.urlopen('%s?format=json' % host_url).read()
|
| + prefix = ')]}\'\n'
|
| + repo_infos = json.loads(content[len(prefix):])
|
| +
|
| + repo_to_clone_url = {}
|
| + for repo, repo_info in repo_infos.iteritems():
|
| + repo_to_clone_url[repo] = repo_info['clone_url']
|
| +
|
| + return repo_to_clone_url
|
|
|