Commit 8499fa25 authored by hablich's avatar hablich Committed by Commit bot

[Release] Distinguish between merges and follow-up CLs

With this change mergeinfo.py gets more useful. There is
a distinction between merges and follow-up CLs/ports/reverts.

Also the information is show if the commit is already
rolled/an lkgr/deployed to Canary channel.

Additionally some formatting errors were resolved and
the already existing git wrapper used.

LOG=N
R=machenbach@chromium.org
NOTRY=true

Review URL: https://codereview.chromium.org/1341303002

Cr-Commit-Position: refs/heads/master@{#31043}
parent 2c2848dc
......@@ -7,29 +7,111 @@ import argparse
import os
import sys
from subprocess import call
def print_analysis(gitWorkingDir, hashToSearch):
print '1.) Info'
git_execute(gitWorkingDir, ['status'])
print '2.) Searching for "' + hashToSearch + '"'
print '=====================ORIGINAL COMMIT START====================='
git_execute(gitWorkingDir, ['show', hashToSearch])
from search_related_commits import git_execute
GIT_OPTION_HASH_ONLY = '--pretty=format:%H'
GIT_OPTION_NO_DIFF = '--quiet'
GIT_OPTION_ONELINE = '--oneline'
def describe_commit(git_working_dir, hash_to_search, one_line=False):
if one_line:
return git_execute(git_working_dir, ['show',
GIT_OPTION_NO_DIFF,
GIT_OPTION_ONELINE,
hash_to_search]).strip()
return git_execute(git_working_dir, ['show',
GIT_OPTION_NO_DIFF,
hash_to_search]).strip()
def get_followup_commits(git_working_dir, hash_to_search):
return git_execute(git_working_dir, ['log',
'--grep=' + hash_to_search,
GIT_OPTION_HASH_ONLY,
'master']).strip().splitlines()
def get_merge_commits(git_working_dir, hash_to_search):
merges = get_related_commits_not_on_master(git_working_dir, hash_to_search)
false_merges = get_related_commits_not_on_master(
git_working_dir, 'Cr-Branched-From: ' + hash_to_search)
false_merges = set(false_merges)
return ([merge_commit for merge_commit in merges
if merge_commit not in false_merges])
def get_related_commits_not_on_master(git_working_dir, grep_command):
commits = git_execute(git_working_dir, ['log',
'--all',
'--grep=' + grep_command,
GIT_OPTION_ONELINE,
'--decorate',
'--not',
'master',
GIT_OPTION_HASH_ONLY])
return commits.splitlines()
def get_branches_for_commit(git_working_dir, hash_to_search):
branches = git_execute(git_working_dir, ['branch',
'--contains',
hash_to_search,
'-a']).strip()
branches = branches.splitlines()
return map(str.strip, branches)
def is_rolling(git_working_dir, hash_to_search):
branches = get_branches_for_commit(git_working_dir, hash_to_search)
return 'remotes/origin/roll' in branches
def is_lkgr(git_working_dir, hash_to_search):
branches = get_branches_for_commit(git_working_dir, hash_to_search)
return 'remotes/origin/lkgr' in branches
def get_first_canary(git_working_dir, hash_to_search):
branches = get_branches_for_commit(git_working_dir, hash_to_search)
canaries = ([currentBranch for currentBranch in branches if
currentBranch.startswith('remotes/origin/chromium/')])
canaries.sort()
if len(canaries) == 0:
return 'No Canary coverage'
return canaries[0].split('/')[-1]
def print_analysis(git_working_dir, hash_to_search):
print '1.) Searching for "' + hash_to_search + '"'
print '=====================ORIGINAL COMMIT START==================='
print describe_commit(git_working_dir, hash_to_search)
print '=====================ORIGINAL COMMIT END====================='
print '#####################FOUND MERGES & REVERTS START#####################'
git_execute(gitWorkingDir, ["log",'--all', '--grep='+hashToSearch])
print '#####################FOUND MERGES & REVERTS END#####################'
print '2.) General information:'
print 'Is rolling: ' + str(is_rolling(git_working_dir, hash_to_search))
print 'Is LKGR: ' + str(is_lkgr(git_working_dir, hash_to_search))
print 'Is on Canary: ' + (
str(get_first_canary(git_working_dir, hash_to_search)))
print '3.) Found follow-up commits, reverts and ports:'
followups = get_followup_commits(git_working_dir, hash_to_search)
for followup in followups:
print describe_commit(git_working_dir, followup, True)
print '4.) Found merges:'
merges = get_merge_commits(git_working_dir, hash_to_search)
for currentMerge in merges:
print describe_commit(git_working_dir, currentMerge, True)
print '---Merged to:'
mergeOutput = git_execute(git_working_dir, ['branch',
'--contains',
currentMerge,
'-r']).strip()
print mergeOutput
print 'Finished successfully'
def git_execute(workingDir, commands):
return call(["git", '-C', workingDir] + commands)
if __name__ == '__main__': # pragma: no cover
parser = argparse.ArgumentParser('Tool to check where a git commit was'
' merged and reverted.')
if __name__ == "__main__": # pragma: no cover
parser = argparse.ArgumentParser('Tool to check where a git commit was merged and reverted.')
parser.add_argument("-g", "--git-dir", required=False, default='.',
help="The path to your git working directory.")
parser.add_argument('-g', '--git-dir', required=False, default='.',
help='The path to your git working directory.')
parser.add_argument('hash', nargs=1, help="Hash of the commit to be searched.")
parser.add_argument('hash',
nargs=1,
help='Hash of the commit to be searched.')
args = sys.argv[1:]
options = parser.parse_args(args)
......
......@@ -48,7 +48,7 @@ def _search_related_commits(
return []
# Extract commit position
original_message = _git_execute(
original_message = git_execute(
git_working_dir,
["show", "-s", "--format=%B", start_hash],
verbose)
......@@ -74,13 +74,13 @@ def _search_related_commits(
search_range,
]
found_by_hash = _git_execute(
found_by_hash = git_execute(
git_working_dir, git_args(start_hash), verbose).strip()
if verbose:
print "2.) Found by hash: " + found_by_hash
found_by_commit_pos = _git_execute(
found_by_commit_pos = git_execute(
git_working_dir, git_args(commit_position), verbose).strip()
if verbose:
......@@ -90,7 +90,7 @@ def _search_related_commits(
title = title.replace("[", "\\[")
title = title.replace("]", "\\]")
found_by_title = _git_execute(
found_by_title = git_execute(
git_working_dir, git_args(title), verbose).strip()
if verbose:
......@@ -113,7 +113,7 @@ def _search_related_commits(
return hits
def _find_commits_inbetween(start_hash, end_hash, git_working_dir, verbose):
commits_between = _git_execute(
commits_between = git_execute(
git_working_dir,
["rev-list", "--reverse", start_hash + ".." + end_hash],
verbose)
......@@ -129,7 +129,7 @@ def _remove_duplicates(array):
no_duplicates.append(current)
return no_duplicates
def _git_execute(working_dir, args, verbose=False):
def git_execute(working_dir, args, verbose=False):
command = ["git", "-C", working_dir] + args
if verbose:
print "Git working dir: " + working_dir
......@@ -145,7 +145,7 @@ def _git_execute(working_dir, args, verbose=False):
return output
def _pretty_print_entry(hash, git_dir, pre_text, verbose):
text_to_print = _git_execute(
text_to_print = git_execute(
git_dir,
["show",
"--quiet",
......@@ -164,7 +164,7 @@ def main(options):
options.verbose)
sort_key = lambda x: (
_git_execute(
git_execute(
options.git_dir,
["show", "--quiet", "--date=iso", x, "--format=%ad"],
options.verbose)).strip()
......
#!/usr/bin/env python
# Copyright 2015 the V8 project 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 mergeinfo
import shutil
import unittest
from collections import namedtuple
from os import path
from subprocess import Popen, PIPE, check_call
TEST_CONFIG = {
"GIT_REPO": "/tmp/test-v8-search-related-commits",
}
class TestMergeInfo(unittest.TestCase):
base_dir = TEST_CONFIG["GIT_REPO"]
def _execute_git(self, git_args):
fullCommand = ["git", "-C", self.base_dir] + git_args
p = Popen(args=fullCommand, stdin=PIPE,
stdout=PIPE, stderr=PIPE)
output, err = p.communicate()
rc = p.returncode
if rc != 0:
raise Exception(err)
return output
def setUp(self):
if path.exists(self.base_dir):
shutil.rmtree(self.base_dir)
check_call(["git", "init", self.base_dir])
# Initial commit
message = '''Initial commit'''
self._make_empty_commit(message)
def tearDown(self):
if path.exists(self.base_dir):
shutil.rmtree(self.base_dir)
def _assert_correct_standard_result(
self, result, all_commits, hash_of_first_commit):
self.assertEqual(len(result), 1, "Master commit not found")
self.assertTrue(
result.get(hash_of_first_commit),
"Master commit is wrong")
self.assertEqual(
len(result[hash_of_first_commit]),
1,
"Child commit not found")
self.assertEqual(
all_commits[2],
result[hash_of_first_commit][0],
"Child commit wrong")
def _get_commits(self):
commits = self._execute_git(
["log", "--format=%H", "--reverse"]).splitlines()
return commits
def _make_empty_commit(self, message):
self._execute_git(["commit", "--allow-empty", "-m", message])
return self._get_commits()[-1]
def testCanDescribeCommit(self):
commits = self._get_commits()
hash_of_first_commit = commits[0]
result = mergeinfo.describe_commit(
self.base_dir,
hash_of_first_commit).splitlines()
self.assertEqual(
result[0],
'commit ' + hash_of_first_commit)
def testCanDescribeCommitSingleLine(self):
commits = self._get_commits()
hash_of_first_commit = commits[0]
result = mergeinfo.describe_commit(
self.base_dir,
hash_of_first_commit, True).splitlines()
self.assertEqual(
str(result[0]),
str(hash_of_first_commit[0:7]) + ' Initial commit')
def testSearchFollowUpCommits(self):
commits = self._get_commits()
hash_of_first_commit = commits[0]
message = 'Follow-up commit of ' + hash_of_first_commit
self._make_empty_commit(message)
self._make_empty_commit(message)
self._make_empty_commit(message)
commits = self._get_commits()
message = 'Not related commit'
self._make_empty_commit(message)
followups = mergeinfo.get_followup_commits(
self.base_dir,
hash_of_first_commit)
self.assertEqual(set(followups), set(commits[1:]))
def testSearchMerges(self):
self._execute_git(['branch', 'test'])
self._execute_git(['checkout', 'master'])
message = 'real initial commit'
self._make_empty_commit(message)
commits = self._get_commits()
hash_of_first_commit = commits[0]
self._execute_git(['checkout', 'test'])
message = 'Not related commit'
self._make_empty_commit(message)
# This should be found
message = 'Merge ' + hash_of_first_commit
hash_of_hit = self._make_empty_commit(message)
# This should be ignored
message = 'Cr-Branched-From: ' + hash_of_first_commit
hash_of_ignored = self._make_empty_commit(message)
self._execute_git(['checkout', 'master'])
followups = mergeinfo.get_followup_commits(
self.base_dir,
hash_of_first_commit)
# Check if follow ups and merges are not overlapping
self.assertEqual(len(followups), 0)
message = 'Follow-up commit of ' + hash_of_first_commit
hash_of_followup = self._make_empty_commit(message)
merges = mergeinfo.get_merge_commits(self.base_dir, hash_of_first_commit)
# Check if follow up is ignored
self.assertTrue(hash_of_followup not in merges)
# Check for proper return of merges
self.assertTrue(hash_of_hit in merges)
self.assertTrue(hash_of_ignored not in merges)
def testIsRolling(self):
commits = self._get_commits()
hash_of_first_commit = commits[0]
self._make_empty_commit('This one is the roll head')
self._execute_git(['branch', 'remotes/origin/roll'])
hash_of_not_rolled = self._make_empty_commit('This one is not yet rolled')
self.assertTrue(mergeinfo.is_rolling(
self.base_dir, hash_of_first_commit))
self.assertFalse(mergeinfo.is_rolling(
self.base_dir, hash_of_not_rolled))
def testIsLkgr(self):
commits = self._get_commits()
hash_of_first_commit = commits[0]
self._make_empty_commit('This one is the lkgr head')
self._execute_git(['branch', 'remotes/origin/lkgr'])
hash_of_not_lkgr = self._make_empty_commit('This one is not yet lkgr')
self.assertTrue(mergeinfo.is_lkgr(
self.base_dir, hash_of_first_commit))
self.assertFalse(mergeinfo.is_lkgr(
self.base_dir, hash_of_not_lkgr))
def testShowFirstCanary(self):
commits = self._get_commits()
hash_of_first_commit = commits[0]
self.assertEqual(mergeinfo.get_first_canary(
self.base_dir, hash_of_first_commit), 'No Canary coverage')
self._execute_git(['branch', 'remotes/origin/chromium/2345'])
self._execute_git(['branch', 'remotes/origin/chromium/2346'])
self.assertEqual(mergeinfo.get_first_canary(
self.base_dir, hash_of_first_commit), '2345')
if __name__ == "__main__":
unittest.main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment