From 113eb2131931013ee1ec3b3a282f109ce7b37f69 Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Sat, 16 Jun 2018 16:03:19 -0700 Subject: [PATCH] Validate a branch that we parse when running cherry_picker --continue When running cherry_picker --continue we count on being able to get certain information from the branch's name which cherry_picker constructed earlier. Verify as best we can that the branch name is one which cherry_picker could have constructed. Relies on the changes here: https://github.com/python/core-workflow/pull/265 (which does the work of one of the validations) --- cherry_picker/cherry_picker/cherry_picker.py | 34 ++++++++++++++++---- cherry_picker/cherry_picker/test.py | 27 +++++++++++++--- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/cherry_picker/cherry_picker/cherry_picker.py b/cherry_picker/cherry_picker/cherry_picker.py index bf0d516..eb2fdf2 100755 --- a/cherry_picker/cherry_picker/cherry_picker.py +++ b/cherry_picker/cherry_picker/cherry_picker.py @@ -74,12 +74,7 @@ def upstream(self): @property def sorted_branches(self): - def version_from_branch(branch): - try: - return tuple(map(int, re.match(r'^.*(?P\d+(\.\d+)+).*$', branch).groupdict()['version'].split('.'))) - except AttributeError as attr_err: - raise ValueError(f'Branch {branch} seems to not have a version in its name.') from attr_err - + """Return the branches to cherry-pick to, sorted by version""" return sorted( self.branches, reverse=True, @@ -423,9 +418,36 @@ def get_base_branch(cherry_pick_branch): return '2.7' from 'backport-sha-2.7' """ prefix, sha, base_branch = cherry_pick_branch.split('-', 2) + + if prefix != 'backport': + raise ValueError('branch name is not prefixed with "backport-". Is this a cherry_picker branch?') + + if not re.match('[0-9a-f]{7,40}', sha): + raise ValueError(f'branch name has an invalid sha: {sha}') + + cmd = ['git', 'log', '-r', sha] + try: + subprocess.check_output(cmd, stderr=subprocess.STDOUT) + except subprocess.SubprocessError: + raise ValueError(f'The sha listed in the branch name, {sha}, is not present in the repository') + + # Subject the parsed base_branch to the same tests as when we generated it + # This throws a ValueError if the base_branch doesn't need our requirements + version_from_branch(base_branch) + return base_branch +def version_from_branch(branch): + """ + return version information from a git branch name + """ + try: + return tuple(map(int, re.match(r'^.*(?P\d+(\.\d+)+).*$', branch).groupdict()['version'].split('.'))) + except AttributeError as attr_err: + raise ValueError(f'Branch {branch} seems to not have a version in its name.') from attr_err + + def get_current_branch(): """ Return the current branch diff --git a/cherry_picker/cherry_picker/test.py b/cherry_picker/cherry_picker/test.py index 2fcfd57..52e46ab 100644 --- a/cherry_picker/cherry_picker/test.py +++ b/cherry_picker/cherry_picker/test.py @@ -32,19 +32,36 @@ def changedir(d): os.chdir(cwd) -def test_get_base_branch(): - # The format of cherry-pick branches we create are "backport-{SHA}-{base_branch}" - cherry_pick_branch = 'backport-afc23f4-2.7' +@mock.patch('subprocess.check_output') +def test_get_base_branch(subprocess_check_output): + # The format of cherry-pick branches we create are:: + # backport-{SHA}-{base_branch} + subprocess_check_output.return_value = b'22a594a0047d7706537ff2ac676cdc0f1dcb329c' + cherry_pick_branch = 'backport-22a594a-2.7' result = get_base_branch(cherry_pick_branch) assert result == '2.7' -def test_get_base_branch_which_has_dashes(): - cherry_pick_branch ='backport-afc23f4-baseprefix-2.7-basesuffix' +@mock.patch('subprocess.check_output') +def test_get_base_branch_which_has_dashes(subprocess_check_output): + subprocess_check_output.return_value = b'22a594a0047d7706537ff2ac676cdc0f1dcb329c' + cherry_pick_branch = 'backport-22a594a-baseprefix-2.7-basesuffix' result = get_base_branch(cherry_pick_branch) assert result == 'baseprefix-2.7-basesuffix' +@pytest.mark.parametrize('cherry_pick_branch', ['backport-22a594a', # Not enough fields + 'prefix-22a594a-2.7', # Not the prefix we were expecting + 'backport-22a594a-base', # No version info in the base branch + ] + ) +@mock.patch('subprocess.check_output') +def test_get_base_branch_invalid(subprocess_check_output, cherry_pick_branch): + subprocess_check_output.return_value = b'22a594a0047d7706537ff2ac676cdc0f1dcb329c' + with pytest.raises(ValueError): + get_base_branch(cherry_pick_branch) + + @mock.patch('subprocess.check_output') def test_get_current_branch(subprocess_check_output): subprocess_check_output.return_value = b'master'