def _ParseChangeLogFromLogData(self, data): change_info = commit_util.ExtractChangeInfo(data['message'], self._ref) touched_files = [] for file_diff in data['tree_diff']: change_type = file_diff['type'].lower() if not diff.IsKnownChangeType(change_type): raise Exception('Unknown change type "%s"' % change_type) touched_files.append( FileChangeInfo(change_type, file_diff['old_path'], file_diff['new_path'])) reverted_revision = commit_util.GetRevertedRevision(data['message']) url = '%s/+/%s' % (self.repo_url, data['commit']) return ChangeLog(self._ContributorFromDict(data['author']), self._ContributorFromDict(data['committer']), data['commit'], change_info.get('commit_position'), data['message'], touched_files, url, change_info.get('code_review_url'), reverted_revision, change_info.get('host'), change_info.get('change_id'))
def testExtractChangeInfo(self): testcases = [{ 'message': 'balabala...\n' '\n' 'BUG=604502\n' '\n' 'Review-Url: https://codereview.chromium.org/1927593004\n' 'Cr-Commit-Position: refs/heads/master@{#390254}\n', 'commit_position': 390254, 'code_review_url': 'https://codereview.chromium.org/1927593004', 'change_id': '1927593004', 'host': 'codereview.chromium.org', }, { 'message': 'balabala...\n' '\n' 'BUG=409934\n' '\n' 'Review URL: https://codereview.chromium.org/547753003\n' '\n' 'Cr-Commit-Position: refs/heads/master@{#293661}', 'commit_position': 293661, 'code_review_url': 'https://codereview.chromium.org/547753003', 'change_id': '547753003', 'host': 'codereview.chromium.org', }, { 'message': 'Review URL: https://codereview.chromium.org/469523002\n' '\n' 'Cr-Commit-Position: refs/heads/master@{#289120}', 'commit_position': 289120, 'code_review_url': 'https://codereview.chromium.org/469523002', 'change_id': '469523002', 'host': 'codereview.chromium.org', }, { 'message': 'balabala...\n' '\n' 'balabala...\n' '\n' '[email protected]\n' '\n' 'Review URL: https://codereview.chromium.org/469523002\n', 'commit_position': None, 'code_review_url': 'https://codereview.chromium.org/469523002', 'change_id': '469523002', 'host': 'codereview.chromium.org', }, { 'message': None, 'commit_position': None, 'code_review_url': None, 'change_id': None, 'host': None, }, { 'message': 'abc', 'commit_position': None, 'code_review_url': None, 'change_id': None, 'host': None, }, { 'message': 'balabala...\n' '\n' 'balabala...\n' '\n' '[email protected]\n' '\n' 'Change-Id: Iaa54f242b5b2fa10870503ef88291b9422cb47ca\n' 'Reviewed-on: https://chromium-review.googlesource.com/45425\n' 'Cr-Commit-Position: refs/heads/master@{#456563}', 'commit_position': 456563, 'code_review_url': 'https://chromium-review.googlesource.com/q/' 'Iaa54f242b5b2fa10870503ef88291b9422cb47ca', 'change_id': 'Iaa54f242b5b2fa10870503ef88291b9422cb47ca', 'host': 'chromium-review.googlesource.com', }] for testcase in testcases: change_info = commit_util.ExtractChangeInfo(testcase['message']) self.assertEqual(change_info.get('commit_position'), testcase['commit_position']) self.assertEqual(change_info.get('code_review_url'), testcase['code_review_url']) self.assertEqual(change_info.get('host'), testcase['host']) self.assertEqual(change_info.get('change_id'), testcase['change_id'])
def __call__(self, output, repo_url): # pylint:disable=W """Parses output of 'git log --pretty=format:<format>. For example: Git changelog output is: commit 21a8979218c096f4a96b07b67c9531f5f09e28a3 tree 7d9a79c9b060c9a030abe20a8429d2b81ca1d4db parents 9640406d426a2d153b16e1d9ae7f9105268b36c9 author Test author-email [email protected] author-time 2016-10-24 22:21:45 committer Test committer-email [email protected] committer-time 2016-10-24 22:25:45 --Message start-- Commit messages... --Message end-- :100644 100644 25f95f c766f1 M src/a/delta/git_parsers.py Returns: Parsed ChangeLog object. """ if not output: return None is_message_line = False info = { 'author': {}, 'committer': {}, 'message': '', 'touched_files': [] } for line in output.splitlines(): if MESSAGE_START_PATTERN.match(line): is_message_line = True continue if MESSAGE_END_PATTERN.match(line): is_message_line = False # Remove the added '\n' at the end. info['message'] = info['message'][:-1] continue if is_message_line: info['message'] += line + '\n' elif COMMIT_HASH_PATTERN.match(line): info['revision'] = COMMIT_HASH_PATTERN.match(line).group(1) elif AUTHOR_NAME_PATTERN.match(line): info['author']['name'] = AUTHOR_NAME_PATTERN.match(line).group( 1) elif AUTHOR_MAIL_PATTERN.match(line): info['author']['email'] = commit_util.NormalizeEmail( AUTHOR_MAIL_PATTERN.match(line).group(1)) elif AUTHOR_TIME_PATTERN.match(line): info['author']['time'] = datetime.strptime( AUTHOR_TIME_PATTERN.match(line).group(1), DATETIME_FORMAT) elif COMMITTER_NAME_PATTERN.match(line): info['committer']['name'] = ( COMMITTER_NAME_PATTERN.match(line).group(1)) elif COMMITTER_MAIL_PATTERN.match(line): info['committer']['email'] = commit_util.NormalizeEmail( COMMITTER_MAIL_PATTERN.match(line).group(1)) elif COMMITTER_TIME_PATTERN.match(line): info['committer']['time'] = datetime.strptime( COMMITTER_TIME_PATTERN.match(line).group(1), DATETIME_FORMAT) elif (CHANGED_FILE_PATTERN1.match(line) or CHANGED_FILE_PATTERN2.match(line)): match = (CHANGED_FILE_PATTERN1.match(line) or CHANGED_FILE_PATTERN2.match(line)) # For modify, add, delete, the pattern is like: # :100644 100644 df565d 6593e M modules/audio_coding/BUILD.gn # For rename, copy, the pattern is like: # :100644 100644 3f2e 20a5 R078 path1 path2 info['touched_files'].append( GetFileChangeInfo( GetChangeType(match.group(5)), match.group(6), None if len(match.groups()) < 7 else match.group(7))) # If commit is not parsed, the changelog will be {'author': {}, 'committer': # {}, 'message': ''}, return None instead. if not 'revision' in info: return None change_info = commit_util.ExtractChangeInfo(info['message']) info['commit_position'] = change_info.get('commit_position') info['code_review_url'] = change_info.get('code_review_url') info['reverted_revision'] = commit_util.GetRevertedRevision( info['message']) info['commit_url'] = '%s/+/%s' % (repo_url, info['revision']) return ChangeLog.FromDict(info)