Skip to content

Instantly share code, notes, and snippets.

@dolph
Created August 24, 2015 14:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dolph/cbcc5eb49558065ef36b to your computer and use it in GitHub Desktop.
Save dolph/cbcc5eb49558065ef36b to your computer and use it in GitHub Desktop.
Attempt to flatten gerrit review sequences
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import argparse
import subprocess
def test_cherry_pick(branch, sequence):
subprocess.check_call(
['git', 'ready', branch])
try:
for git_sha in sequence:
subprocess.check_call(
['git', 'cherry-pick', '--quiet', '%s' % git_sha],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError:
subprocess.check_call(
['git', 'cherry-pick', '--abort'],
stderr=subprocess.STDOUT)
return False
else:
return True
def review_numbers_to_git_shas(reviews):
"""Convert a list of review numbers to git SHAs.
This is useful for improving cherry-picking performance.
"""
git_shas = []
for review in reviews:
subprocess.check_call(
['git', 'review', '-d', '%s' % review])
git_sha = subprocess.check_output(
['git', 'rev-parse', 'HEAD']).strip()
git_shas.append(git_sha)
return git_shas
def split_sequence(branch, sequence):
if len(sequence) == 1:
return False
for git_sha in reversed(sequence):
index = sequence.index(git_sha)
# sequence A is already known to work
sequence_a = sequence[:index]
# sequence B is a splice that must be tested
sequence_b = sequence[:index - 1] + sequence[index:]
if test_cherry_pick(branch, sequence_b):
print('Split successfully: %s' % sequence_b)
return sequence_a, sequence_b
return False
def clean_up_sequences(sequences):
sequences.sort(lambda x, y: cmp(len(x), len(y)))
redundant_sequences = []
for i, sequence_a in enumerate(sequences):
for sequence_b in sequences[i + 1:]:
for k in range(len(sequence_a)):
if sequence_a[k] == sequence_b[k]:
redundant_sequences.append(sequence_a)
for redundant_sequence in redundant_sequences:
if redundant_sequence in sequences:
sequences.remove(redundant_sequence)
def main(branch, reviews, test):
sequences = [review_numbers_to_git_shas(reviews)]
final_sequences = []
try:
while sequences:
sequence = sequences.pop()
split = split_sequence(branch, sequence)
if split:
sequence_a, sequence_b = split
sequences.append(sequence_a)
sequences.append(sequence_b)
else:
final_sequences.append(sequence)
finally:
clean_up_sequences(final_sequences)
print(final_sequences)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'--test',
action='store_true',
help='Test each patch, as opposed to checking cherry-pick '
'compatibility.')
parser.add_argument(
'branch',
help='The branch to which reviews should be cherry-picked.')
parser.add_argument(
'reviews',
type=int,
nargs='+',
help='The sequence of reviews to squash.')
args = parser.parse_args()
main(args.branch, args.reviews, args.test)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment