aboutsummaryrefslogtreecommitdiff
path: root/llvm_tools/git.py
diff options
context:
space:
mode:
Diffstat (limited to 'llvm_tools/git.py')
-rwxr-xr-xllvm_tools/git.py105
1 files changed, 57 insertions, 48 deletions
diff --git a/llvm_tools/git.py b/llvm_tools/git.py
index 0f56aa0d..ea4ce3d2 100755
--- a/llvm_tools/git.py
+++ b/llvm_tools/git.py
@@ -1,46 +1,36 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
# Copyright 2020 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Git helper functions."""
-
import collections
import os
+from pathlib import Path
import re
import subprocess
import tempfile
+from typing import Iterable, Optional, Union
CommitContents = collections.namedtuple("CommitContents", ["url", "cl_number"])
-def InChroot():
- """Returns True if currently in the chroot."""
- return "CROS_WORKON_SRCROOT" in os.environ
-
-
-def VerifyOutsideChroot():
- """Checks whether the script invoked was executed in the chroot.
-
- Raises:
- AssertionError: The script was run inside the chroot.
- """
-
- assert not InChroot(), "Script should be run outside the chroot."
+def IsFullGitSHA(s: str) -> bool:
+ """Returns if `s` looks like a git SHA."""
+ return len(s) == 40 and all(x.isdigit() or "a" <= x <= "f" for x in s)
-def CreateBranch(repo, branch):
+def CreateBranch(repo: Union[Path, str], branch: str) -> None:
"""Creates a branch in the given repo.
Args:
- repo: The absolute path to the repo.
- branch: The name of the branch to create.
+ repo: The absolute path to the repo.
+ branch: The name of the branch to create.
Raises:
- ValueError: Failed to create a repo in that directory.
+ ValueError: Failed to create a repo in that directory.
"""
if not os.path.isdir(repo):
@@ -51,57 +41,76 @@ def CreateBranch(repo, branch):
subprocess.check_output(["repo", "start", branch], cwd=repo)
-def DeleteBranch(repo, branch):
+def DeleteBranch(repo: Union[Path, str], branch: str) -> None:
"""Deletes a branch in the given repo.
Args:
- repo: The absolute path of the repo.
- branch: The name of the branch to delete.
+ repo: The absolute path of the repo.
+ branch: The name of the branch to delete.
Raises:
- ValueError: Failed to delete the repo in that directory.
+ ValueError: Failed to delete the repo in that directory.
"""
if not os.path.isdir(repo):
raise ValueError("Invalid directory path provided: %s" % repo)
- subprocess.check_output(["git", "-C", repo, "checkout", "cros/main"])
+ def run_checked(cmd):
+ subprocess.run(["git", "-C", repo] + cmd, check=True)
- subprocess.check_output(["git", "-C", repo, "reset", "HEAD", "--hard"])
+ run_checked(["checkout", "-q", "m/main"])
+ run_checked(["reset", "-q", "HEAD", "--hard"])
+ run_checked(["branch", "-q", "-D", branch])
+
+
+def CommitChanges(
+ repo: Union[Path, str], commit_messages: Iterable[str]
+) -> None:
+ """Commit changes without uploading them.
+
+ Args:
+ repo: The absolute path to the repo where changes were made.
+ commit_messages: Messages to concatenate to form the commit message.
+ """
+ if not os.path.isdir(repo):
+ raise ValueError("Invalid path provided: %s" % repo)
- subprocess.check_output(["git", "-C", repo, "branch", "-D", branch])
+ # Create a git commit.
+ with tempfile.NamedTemporaryFile(mode="w+t", encoding="utf-8") as f:
+ f.write("\n".join(commit_messages))
+ f.flush()
+
+ subprocess.check_output(["git", "commit", "-F", f.name], cwd=repo)
-def UploadChanges(repo, branch, commit_messages, reviewers=None, cc=None):
+def UploadChanges(
+ repo: Union[Path, str],
+ branch: str,
+ reviewers: Optional[Iterable[str]] = None,
+ cc: Optional[Iterable[str]] = None,
+ wip: bool = False,
+) -> CommitContents:
"""Uploads the changes in the specifed branch of the given repo for review.
Args:
- repo: The absolute path to the repo where changes were made.
- branch: The name of the branch to upload.
- commit_messages: A string of commit message(s) (i.e. '[message]'
- of the changes made.
- reviewers: A list of reviewers to add to the CL.
- cc: A list of contributors to CC about the CL.
+ repo: The absolute path to the repo where changes were made.
+ branch: The name of the branch to upload.
+ of the changes made.
+ reviewers: A list of reviewers to add to the CL.
+ cc: A list of contributors to CC about the CL.
+ wip: Whether to upload the change as a work-in-progress.
Returns:
- A nametuple that has two (key, value) pairs, where the first pair is the
- Gerrit commit URL and the second pair is the change list number.
+ A CommitContents value containing the commit URL and change list number.
Raises:
- ValueError: Failed to create a commit or failed to upload the
- changes for review.
+ ValueError: Failed to create a commit or failed to upload the
+ changes for review.
"""
if not os.path.isdir(repo):
raise ValueError("Invalid path provided: %s" % repo)
- # Create a git commit.
- with tempfile.NamedTemporaryFile(mode="w+t") as f:
- f.write("\n".join(commit_messages))
- f.flush()
-
- subprocess.check_output(["git", "commit", "-F", f.name], cwd=repo)
-
# Upload the changes for review.
git_args = [
"repo",
@@ -114,6 +123,8 @@ def UploadChanges(repo, branch, commit_messages, reviewers=None, cc=None):
if cc:
git_args.append(f'--cc={",".join(cc)}')
+ if wip:
+ git_args.append("--wip")
out = subprocess.check_output(
git_args,
@@ -123,13 +134,11 @@ def UploadChanges(repo, branch, commit_messages, reviewers=None, cc=None):
)
print(out)
-
+ # Matches both internal and external CLs.
found_url = re.search(
- r"https://chromium-review.googlesource.com/c/"
- r"chromiumos/overlays/chromiumos-overlay/\+/([0-9]+)",
+ r"https?://[\w-]*-review.googlesource.com/c/.*/([0-9]+)",
out.rstrip(),
)
-
if not found_url:
raise ValueError("Failed to find change list URL.")