• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/main'])
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, reviewers=None, cc=None):
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    reviewers: A list of reviewers to add to the CL.
84    cc: A list of contributors to CC about the CL.
85
86  Returns:
87    A nametuple that has two (key, value) pairs, where the first pair is the
88    Gerrit commit URL and the second pair is the change list number.
89
90  Raises:
91    ValueError: Failed to create a commit or failed to upload the
92    changes for review.
93  """
94
95  if not os.path.isdir(repo):
96    raise ValueError('Invalid path provided: %s' % repo)
97
98  # Create a git commit.
99  with tempfile.NamedTemporaryFile(mode='w+t') as f:
100    f.write('\n'.join(commit_messages))
101    f.flush()
102
103    subprocess.check_output(['git', 'commit', '-F', f.name], cwd=repo)
104
105  # Upload the changes for review.
106  git_args = [
107      'repo',
108      'upload',
109      '--yes',
110      f'--reviewers={",".join(reviewers)}' if reviewers else '--ne',
111      '--no-verify',
112      f'--br={branch}',
113  ]
114
115  if cc:
116    git_args.append(f'--cc={",".join(cc)}')
117
118  out = subprocess.check_output(
119      git_args,
120      stderr=subprocess.STDOUT,
121      cwd=repo,
122      encoding='utf-8',
123  )
124
125  print(out)
126
127  found_url = re.search(
128      r'https://chromium-review.googlesource.com/c/'
129      r'chromiumos/overlays/chromiumos-overlay/\+/([0-9]+)', out.rstrip())
130
131  if not found_url:
132    raise ValueError('Failed to find change list URL.')
133
134  return CommitContents(
135      url=found_url.group(0), cl_number=int(found_url.group(1)))
136