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 9from __future__ import print_function 10 11import collections 12import os 13import re 14import subprocess 15import tempfile 16 17CommitContents = collections.namedtuple('CommitContents', ['url', 'cl_number']) 18 19 20def InChroot(): 21 """Returns True if currently in the chroot.""" 22 return 'CROS_WORKON_SRCROOT' in os.environ 23 24 25def 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 35def 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 49 subprocess.check_output(['git', '-C', repo, 'reset', 'HEAD', '--hard']) 50 51 subprocess.check_output(['repo', 'start', branch], cwd=repo) 52 53 54def 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 68 subprocess.check_output(['git', '-C', repo, 'checkout', 'cros/master']) 69 70 subprocess.check_output(['git', '-C', repo, 'reset', 'HEAD', '--hard']) 71 72 subprocess.check_output(['git', '-C', repo, 'branch', '-D', branch]) 73 74 75def 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 101 subprocess.check_output(['git', 'commit', '-F', f.name], cwd=repo) 102 103 # Upload the changes for review. 104 out = subprocess.check_output( 105 ['repo', 'upload', '--yes', '--ne', '--no-verify', 106 '--br=%s' % branch], 107 stderr=subprocess.STDOUT, 108 cwd=repo, 109 encoding='utf-8') 110 111 print(out) 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))) 122