diff options
Diffstat (limited to 'llvm_tools/git.py')
-rwxr-xr-x | llvm_tools/git.py | 105 |
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.") |