Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # -*- coding: utf-8 -*- |
| 3 | # Copyright 2020 The Chromium OS Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | |
| 7 | """Git helper functions.""" |
| 8 | |
| 9 | from __future__ import print_function |
| 10 | |
| 11 | import collections |
| 12 | import os |
| 13 | import re |
| 14 | import subprocess |
| 15 | import tempfile |
| 16 | |
| 17 | CommitContents = collections.namedtuple('CommitContents', ['url', 'cl_number']) |
| 18 | |
| 19 | |
| 20 | def InChroot(): |
| 21 | """Returns True if currently in the chroot.""" |
| 22 | return 'CROS_WORKON_SRCROOT' in os.environ |
| 23 | |
| 24 | |
| 25 | def VerifyOutsideChroot(): |
| 26 | """Checks whether the script invoked was executed in the chroot. |
| 27 | |
| 28 | Raises: |
| 29 | AssertionError: The script was run inside the chroot. |
| 30 | """ |
| 31 | |
| 32 | assert not InChroot(), 'Script should be run outside the chroot.' |
| 33 | |
| 34 | |
| 35 | def CreateBranch(repo, branch): |
| 36 | """Creates a branch in the given repo. |
| 37 | |
| 38 | Args: |
| 39 | repo: The absolute path to the repo. |
| 40 | branch: The name of the branch to create. |
| 41 | |
| 42 | Raises: |
| 43 | ValueError: Failed to create a repo in that directory. |
| 44 | """ |
| 45 | |
| 46 | if not os.path.isdir(repo): |
| 47 | raise ValueError('Invalid directory path provided: %s' % repo) |
| 48 | |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 49 | subprocess.check_output(['git', '-C', repo, 'reset', 'HEAD', '--hard']) |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 50 | |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 51 | subprocess.check_output(['repo', 'start', branch], cwd=repo) |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 52 | |
| 53 | |
| 54 | def DeleteBranch(repo, branch): |
| 55 | """Deletes a branch in the given repo. |
| 56 | |
| 57 | Args: |
| 58 | repo: The absolute path of the repo. |
| 59 | branch: The name of the branch to delete. |
| 60 | |
| 61 | Raises: |
| 62 | ValueError: Failed to delete the repo in that directory. |
| 63 | """ |
| 64 | |
| 65 | if not os.path.isdir(repo): |
| 66 | raise ValueError('Invalid directory path provided: %s' % repo) |
| 67 | |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 68 | subprocess.check_output(['git', '-C', repo, 'checkout', 'cros/master']) |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 69 | |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 70 | subprocess.check_output(['git', '-C', repo, 'reset', 'HEAD', '--hard']) |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 71 | |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 72 | subprocess.check_output(['git', '-C', repo, 'branch', '-D', branch]) |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 73 | |
| 74 | |
| 75 | def UploadChanges(repo, branch, commit_messages): |
| 76 | """Uploads the changes in the specifed branch of the given repo for review. |
| 77 | |
| 78 | Args: |
| 79 | repo: The absolute path to the repo where changes were made. |
| 80 | branch: The name of the branch to upload. |
| 81 | commit_messages: A string of commit message(s) (i.e. '[message]' |
| 82 | of the changes made. |
| 83 | |
| 84 | Returns: |
| 85 | A nametuple that has two (key, value) pairs, where the first pair is the |
| 86 | Gerrit commit URL and the second pair is the change list number. |
| 87 | |
| 88 | Raises: |
| 89 | ValueError: Failed to create a commit or failed to upload the |
| 90 | changes for review. |
| 91 | """ |
| 92 | |
| 93 | if not os.path.isdir(repo): |
| 94 | raise ValueError('Invalid path provided: %s' % repo) |
| 95 | |
| 96 | # Create a git commit. |
| 97 | with tempfile.NamedTemporaryFile(mode='w+t') as f: |
| 98 | f.write('\n'.join(commit_messages)) |
| 99 | f.flush() |
| 100 | |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 101 | subprocess.check_output(['git', 'commit', '-F', f.name], cwd=repo) |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 102 | |
| 103 | # Upload the changes for review. |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 104 | out = subprocess.check_output( |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 105 | ['repo', 'upload', '--yes', '--ne', '--no-verify', |
| 106 | '--br=%s' % branch], |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 107 | stderr=subprocess.STDOUT, |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 108 | cwd=repo, |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 109 | encoding='utf-8') |
| 110 | |
Jian Cai | fbefdc4 | 2020-04-30 15:29:03 -0700 | [diff] [blame^] | 111 | print(out) |
Jian Cai | c16daa1 | 2020-04-15 17:53:41 -0700 | [diff] [blame] | 112 | |
| 113 | found_url = re.search( |
| 114 | r'https://chromium-review.googlesource.com/c/' |
| 115 | r'chromiumos/overlays/chromiumos-overlay/\+/([0-9]+)', out.rstrip()) |
| 116 | |
| 117 | if not found_url: |
| 118 | raise ValueError('Failed to find change list URL.') |
| 119 | |
| 120 | return CommitContents( |
| 121 | url=found_url.group(0), cl_number=int(found_url.group(1))) |