Formatting: Format all python code with black.
This CL is probably not what you're looking for, it's only
automated formatting. Ignore it with
`git blame --ignore-rev <revision>` for this commit.
BUG=b:233893248
TEST=CQ
Change-Id: I66591d7a738d241aed3290138c0f68065ab10a6d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/3879174
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Tested-by: Alex Klein <saklein@chromium.org>
diff --git a/scripts/cros_merge_to_branch.py b/scripts/cros_merge_to_branch.py
index 885ef62..309fc90 100644
--- a/scripts/cros_merge_to_branch.py
+++ b/scripts/cros_merge_to_branch.py
@@ -51,258 +51,331 @@
def _GetParser():
- """Returns the parser to use for this module."""
- parser = commandline.ArgumentParser(description=__doc__)
- parser.add_argument('-d', '--draft', default=False, action='store_true',
- help='upload a draft to Gerrit rather than a change')
- parser.add_argument('-n', '--dry-run', default=False, action='store_true',
- dest='dryrun',
- help='apply changes locally but do not upload them')
- parser.add_argument('-e', '--email',
- help='use this email instead of the email you would '
- 'upload changes as; required w/--nomirror')
- parser.add_argument('--nomirror', default=True, dest='mirror',
- action='store_false',
- help='checkout git repo directly; requires --email')
- parser.add_argument('--nowipe', default=True, dest='wipe',
- action='store_false',
- help='do not wipe the work directory after finishing')
- parser.add_argument('change', nargs='+', help='CLs to merge')
- parser.add_argument('branch', help='the branch to merge to')
- return parser
+ """Returns the parser to use for this module."""
+ parser = commandline.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ "-d",
+ "--draft",
+ default=False,
+ action="store_true",
+ help="upload a draft to Gerrit rather than a change",
+ )
+ parser.add_argument(
+ "-n",
+ "--dry-run",
+ default=False,
+ action="store_true",
+ dest="dryrun",
+ help="apply changes locally but do not upload them",
+ )
+ parser.add_argument(
+ "-e",
+ "--email",
+ help="use this email instead of the email you would "
+ "upload changes as; required w/--nomirror",
+ )
+ parser.add_argument(
+ "--nomirror",
+ default=True,
+ dest="mirror",
+ action="store_false",
+ help="checkout git repo directly; requires --email",
+ )
+ parser.add_argument(
+ "--nowipe",
+ default=True,
+ dest="wipe",
+ action="store_false",
+ help="do not wipe the work directory after finishing",
+ )
+ parser.add_argument("change", nargs="+", help="CLs to merge")
+ parser.add_argument("branch", help="the branch to merge to")
+ return parser
def _UploadChangeToBranch(work_dir, patch, branch, draft, dryrun):
- """Creates a new change from GerritPatch |patch| to |branch| from |work_dir|.
+ """Creates a new change from GerritPatch |patch| to |branch| from |work_dir|.
- Args:
- patch: Instance of GerritPatch to upload.
- branch: Branch to upload to.
- work_dir: Local directory where repository is checked out in.
- draft: If True, upload to refs/draft/|branch| rather than refs/for/|branch|.
- dryrun: Don't actually upload a change but go through all the steps up to
- and including git push --dry-run.
+ Args:
+ patch: Instance of GerritPatch to upload.
+ branch: Branch to upload to.
+ work_dir: Local directory where repository is checked out in.
+ draft: If True, upload to refs/draft/|branch| rather than refs/for/|branch|.
+ dryrun: Don't actually upload a change but go through all the steps up to
+ and including git push --dry-run.
- Returns:
- A list of all the gerrit URLs found.
- """
- upload_type = 'drafts' if draft else 'for'
- # Download & setup the patch if need be.
- patch.Fetch(work_dir)
- # Apply the actual change.
- patch.CherryPick(work_dir, inflight=True, leave_dirty=True)
+ Returns:
+ A list of all the gerrit URLs found.
+ """
+ upload_type = "drafts" if draft else "for"
+ # Download & setup the patch if need be.
+ patch.Fetch(work_dir)
+ # Apply the actual change.
+ patch.CherryPick(work_dir, inflight=True, leave_dirty=True)
- # Get the new sha1 after apply.
- new_sha1 = git.GetGitRepoRevision(work_dir)
- reviewers = set()
+ # Get the new sha1 after apply.
+ new_sha1 = git.GetGitRepoRevision(work_dir)
+ reviewers = set()
- # Filter out tags that are added by gerrit and chromite.
- filter_re = re.compile(
- r'((Commit|Trybot)-Ready|Commit-Queue|(Reviewed|Submitted|Tested)-by): ')
+ # Filter out tags that are added by gerrit and chromite.
+ filter_re = re.compile(
+ r"((Commit|Trybot)-Ready|Commit-Queue|(Reviewed|Submitted|Tested)-by): "
+ )
- # Rewrite the commit message all the time. Latest gerrit doesn't seem
- # to like it when you use the same ChangeId on different branches.
- msg = []
- for line in patch.commit_message.splitlines():
- if line.startswith('Reviewed-on: '):
- line = 'Previous-' + line
- elif filter_re.match(line):
- # If the tag is malformed, or the person lacks a name,
- # then that's just too bad -- throw it away.
- ele = re.split(r'[<>@]+', line)
- if len(ele) == 4:
- reviewers.add('@'.join(ele[-3:-1]))
- continue
- msg.append(line)
- msg += ['(cherry picked from commit %s)' % patch.sha1]
- git.RunGit(work_dir, ['commit', '--amend', '-F', '-'],
- input='\n'.join(msg).encode('utf8'))
+ # Rewrite the commit message all the time. Latest gerrit doesn't seem
+ # to like it when you use the same ChangeId on different branches.
+ msg = []
+ for line in patch.commit_message.splitlines():
+ if line.startswith("Reviewed-on: "):
+ line = "Previous-" + line
+ elif filter_re.match(line):
+ # If the tag is malformed, or the person lacks a name,
+ # then that's just too bad -- throw it away.
+ ele = re.split(r"[<>@]+", line)
+ if len(ele) == 4:
+ reviewers.add("@".join(ele[-3:-1]))
+ continue
+ msg.append(line)
+ msg += ["(cherry picked from commit %s)" % patch.sha1]
+ git.RunGit(
+ work_dir,
+ ["commit", "--amend", "-F", "-"],
+ input="\n".join(msg).encode("utf8"),
+ )
- # Get the new sha1 after rewriting the commit message.
- new_sha1 = git.GetGitRepoRevision(work_dir)
+ # Get the new sha1 after rewriting the commit message.
+ new_sha1 = git.GetGitRepoRevision(work_dir)
- # Create and use a LocalPatch to Upload the change to Gerrit.
- local_patch = cros_patch.LocalPatch(
- work_dir, patch.project_url, constants.PATCH_BRANCH,
- patch.tracking_branch, patch.remote, new_sha1)
- for reviewers in (reviewers, ()):
- try:
- return local_patch.Upload(
- patch.project_url, 'refs/%s/%s' % (upload_type, branch),
- carbon_copy=False, dryrun=dryrun, reviewers=reviewers)
- except cros_build_lib.RunCommandError as e:
- if (e.returncode == 128 and
- re.search(r'fatal: user ".*?" not found', e.stderr)):
- logging.warning('Some reviewers were not found (%s); '
- 'dropping them & retrying upload', ' '.join(reviewers))
- continue
- raise
+ # Create and use a LocalPatch to Upload the change to Gerrit.
+ local_patch = cros_patch.LocalPatch(
+ work_dir,
+ patch.project_url,
+ constants.PATCH_BRANCH,
+ patch.tracking_branch,
+ patch.remote,
+ new_sha1,
+ )
+ for reviewers in (reviewers, ()):
+ try:
+ return local_patch.Upload(
+ patch.project_url,
+ "refs/%s/%s" % (upload_type, branch),
+ carbon_copy=False,
+ dryrun=dryrun,
+ reviewers=reviewers,
+ )
+ except cros_build_lib.RunCommandError as e:
+ if e.returncode == 128 and re.search(
+ r'fatal: user ".*?" not found', e.stderr
+ ):
+ logging.warning(
+ "Some reviewers were not found (%s); "
+ "dropping them & retrying upload",
+ " ".join(reviewers),
+ )
+ continue
+ raise
def _SetupWorkDirectoryForPatch(work_dir, patch, branch, manifest, email):
- """Set up local dir for uploading changes to the given patch's project."""
- logging.notice('Setting up dir %s for uploading changes to %s', work_dir,
- patch.project_url)
+ """Set up local dir for uploading changes to the given patch's project."""
+ logging.notice(
+ "Setting up dir %s for uploading changes to %s",
+ work_dir,
+ patch.project_url,
+ )
- # Clone the git repo from reference if we have a pointer to a
- # ManifestCheckout object.
- reference = None
- if manifest:
- # Get the path to the first checkout associated with this change. Since
- # all of the checkouts share git objects, it doesn't matter which checkout
- # we pick.
- path = manifest.FindCheckouts(patch.project)[0]['path']
+ # Clone the git repo from reference if we have a pointer to a
+ # ManifestCheckout object.
+ reference = None
+ if manifest:
+ # Get the path to the first checkout associated with this change. Since
+ # all of the checkouts share git objects, it doesn't matter which checkout
+ # we pick.
+ path = manifest.FindCheckouts(patch.project)[0]["path"]
- reference = os.path.join(constants.SOURCE_ROOT, path)
- if not os.path.isdir(reference):
- logging.error('Unable to locate git checkout: %s', reference)
- logging.error('Did you mean to use --nomirror?')
- # This will do an "raise OSError" with the right values.
- os.open(reference, os.O_DIRECTORY)
- # Use the email if email wasn't specified.
- if not email:
- email = git.GetProjectUserEmail(reference)
+ reference = os.path.join(constants.SOURCE_ROOT, path)
+ if not os.path.isdir(reference):
+ logging.error("Unable to locate git checkout: %s", reference)
+ logging.error("Did you mean to use --nomirror?")
+ # This will do an "raise OSError" with the right values.
+ os.open(reference, os.O_DIRECTORY)
+ # Use the email if email wasn't specified.
+ if not email:
+ email = git.GetProjectUserEmail(reference)
- git.Clone(work_dir, patch.project_url, reference=reference)
+ git.Clone(work_dir, patch.project_url, reference=reference)
- # Set the git committer.
- git.RunGit(work_dir, ['config', '--replace-all', 'user.email', email])
+ # Set the git committer.
+ git.RunGit(work_dir, ["config", "--replace-all", "user.email", email])
- mbranch = git.MatchSingleBranchName(
- work_dir, branch, namespace='refs/remotes/origin/')
- if branch != mbranch:
- logging.notice('Auto resolved branch name "%s" to "%s"', branch, mbranch)
- branch = mbranch
+ mbranch = git.MatchSingleBranchName(
+ work_dir, branch, namespace="refs/remotes/origin/"
+ )
+ if branch != mbranch:
+ logging.notice(
+ 'Auto resolved branch name "%s" to "%s"', branch, mbranch
+ )
+ branch = mbranch
- # Finally, create a local branch for uploading changes to the given remote
- # branch.
- git.CreatePushBranch(
- constants.PATCH_BRANCH, work_dir, sync=False,
- remote_push_branch=git.RemoteRef('ignore', 'origin/%s' % branch))
+ # Finally, create a local branch for uploading changes to the given remote
+ # branch.
+ git.CreatePushBranch(
+ constants.PATCH_BRANCH,
+ work_dir,
+ sync=False,
+ remote_push_branch=git.RemoteRef("ignore", "origin/%s" % branch),
+ )
- return branch
+ return branch
def _ManifestContainsAllPatches(manifest, patches):
- """Returns true if the given manifest contains all the patches.
+ """Returns true if the given manifest contains all the patches.
- Args:
- manifest: an instance of git.Manifest
- patches: a collection of GerritPatch objects.
- """
- for patch in patches:
- if not manifest.FindCheckouts(patch.project):
- logging.error('Your manifest does not have the repository %s for '
- 'change %s. Please re-run with --nomirror and '
- '--email set', patch.project, patch.gerrit_number)
- return False
+ Args:
+ manifest: an instance of git.Manifest
+ patches: a collection of GerritPatch objects.
+ """
+ for patch in patches:
+ if not manifest.FindCheckouts(patch.project):
+ logging.error(
+ "Your manifest does not have the repository %s for "
+ "change %s. Please re-run with --nomirror and "
+ "--email set",
+ patch.project,
+ patch.gerrit_number,
+ )
+ return False
- return True
+ return True
def main(argv):
- parser = _GetParser()
- options = parser.parse_args(argv)
- changes = options.change
- branch = options.branch
+ parser = _GetParser()
+ options = parser.parse_args(argv)
+ changes = options.change
+ branch = options.branch
- try:
- patches = gerrit.GetGerritPatchInfo(changes)
- except ValueError as e:
- logging.error('Invalid patch: %s', e)
- cros_build_lib.Die('Did you swap the branch/gerrit number?')
-
- # Suppress all logging info output unless we're running debug.
- if not options.debug:
- logging.getLogger().setLevel(logging.NOTICE)
-
- # Get a pointer to your repo checkout to look up the local project paths for
- # both email addresses and for using your checkout as a git mirror.
- manifest = None
- if options.mirror:
try:
- manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
- except OSError as e:
- if e.errno == errno.ENOENT:
- logging.error('Unable to locate ChromiumOS checkout: %s',
- constants.SOURCE_ROOT)
- logging.error('Did you mean to use --nomirror?')
- return 1
- raise
- if not _ManifestContainsAllPatches(manifest, patches):
- return 1
- else:
- if not options.email:
- chromium_email = '%s@chromium.org' % os.environ['USER']
- logging.notice('--nomirror set without email, using %s', chromium_email)
- options.email = chromium_email
+ patches = gerrit.GetGerritPatchInfo(changes)
+ except ValueError as e:
+ logging.error("Invalid patch: %s", e)
+ cros_build_lib.Die("Did you swap the branch/gerrit number?")
- index = 0
- work_dir = None
- root_work_dir = tempfile.mkdtemp(prefix='cros_merge_to_branch')
- try:
- for index, (change, patch) in enumerate(zip(changes, patches)):
- # We only clone the project and set the committer the first time.
- work_dir = os.path.join(root_work_dir, patch.project)
- if not os.path.isdir(work_dir):
- branch = _SetupWorkDirectoryForPatch(work_dir, patch, branch, manifest,
- options.email)
+ # Suppress all logging info output unless we're running debug.
+ if not options.debug:
+ logging.getLogger().setLevel(logging.NOTICE)
- # Now that we have the project checked out, let's apply our change and
- # create a new change on Gerrit.
- logging.notice('Uploading change %s to branch %s', change, branch)
- urls = _UploadChangeToBranch(work_dir, patch, branch, options.draft,
- options.dryrun)
- logging.notice('Successfully uploaded %s to %s', change, branch)
- for url in urls:
- if url.endswith('\x1b[K'):
- # Git will often times emit these escape sequences.
- url = url[0:-3]
- logging.notice(' URL: %s', url)
-
- except (cros_build_lib.RunCommandError, cros_patch.ApplyPatchException,
- git.AmbiguousBranchName, OSError) as e:
- # Tell the user how far we got.
- good_changes = changes[:index]
- bad_changes = changes[index:]
-
- logging.warning('############## SOME CHANGES FAILED TO UPLOAD ############')
-
- if good_changes:
- logging.notice(
- 'Successfully uploaded change(s) %s', ' '.join(good_changes))
-
- # Printing out the error here so that we can see exactly what failed. This
- # is especially useful to debug without using --debug.
- logging.error('Upload failed with %s', str(e).strip())
- if not options.wipe:
- logging.error('Not wiping the directory. You can inspect the failed '
- 'change at %s; After fixing the change (if trivial) you can'
- ' try to upload the change by running:\n'
- 'git commit -a -c CHERRY_PICK_HEAD\n'
- 'git push %s HEAD:refs/for/%s', work_dir, patch.project_url,
- branch)
+ # Get a pointer to your repo checkout to look up the local project paths for
+ # both email addresses and for using your checkout as a git mirror.
+ manifest = None
+ if options.mirror:
+ try:
+ manifest = git.ManifestCheckout.Cached(constants.SOURCE_ROOT)
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ logging.error(
+ "Unable to locate ChromiumOS checkout: %s",
+ constants.SOURCE_ROOT,
+ )
+ logging.error("Did you mean to use --nomirror?")
+ return 1
+ raise
+ if not _ManifestContainsAllPatches(manifest, patches):
+ return 1
else:
- logging.error('--nowipe not set thus deleting the work directory. If you '
- 'wish to debug this, re-run the script with change(s) '
- '%s and --nowipe by running:\n %s %s %s --nowipe',
- ' '.join(bad_changes), sys.argv[0], ' '.join(bad_changes),
- branch)
+ if not options.email:
+ chromium_email = "%s@chromium.org" % os.environ["USER"]
+ logging.notice(
+ "--nomirror set without email, using %s", chromium_email
+ )
+ options.email = chromium_email
- # Suppress the stack trace if we're not debugging.
- if options.debug:
- raise
+ index = 0
+ work_dir = None
+ root_work_dir = tempfile.mkdtemp(prefix="cros_merge_to_branch")
+ try:
+ for index, (change, patch) in enumerate(zip(changes, patches)):
+ # We only clone the project and set the committer the first time.
+ work_dir = os.path.join(root_work_dir, patch.project)
+ if not os.path.isdir(work_dir):
+ branch = _SetupWorkDirectoryForPatch(
+ work_dir, patch, branch, manifest, options.email
+ )
+
+ # Now that we have the project checked out, let's apply our change and
+ # create a new change on Gerrit.
+ logging.notice("Uploading change %s to branch %s", change, branch)
+ urls = _UploadChangeToBranch(
+ work_dir, patch, branch, options.draft, options.dryrun
+ )
+ logging.notice("Successfully uploaded %s to %s", change, branch)
+ for url in urls:
+ if url.endswith("\x1b[K"):
+ # Git will often times emit these escape sequences.
+ url = url[0:-3]
+ logging.notice(" URL: %s", url)
+
+ except (
+ cros_build_lib.RunCommandError,
+ cros_patch.ApplyPatchException,
+ git.AmbiguousBranchName,
+ OSError,
+ ) as e:
+ # Tell the user how far we got.
+ good_changes = changes[:index]
+ bad_changes = changes[index:]
+
+ logging.warning(
+ "############## SOME CHANGES FAILED TO UPLOAD ############"
+ )
+
+ if good_changes:
+ logging.notice(
+ "Successfully uploaded change(s) %s", " ".join(good_changes)
+ )
+
+ # Printing out the error here so that we can see exactly what failed. This
+ # is especially useful to debug without using --debug.
+ logging.error("Upload failed with %s", str(e).strip())
+ if not options.wipe:
+ logging.error(
+ "Not wiping the directory. You can inspect the failed "
+ "change at %s; After fixing the change (if trivial) you can"
+ " try to upload the change by running:\n"
+ "git commit -a -c CHERRY_PICK_HEAD\n"
+ "git push %s HEAD:refs/for/%s",
+ work_dir,
+ patch.project_url,
+ branch,
+ )
+ else:
+ logging.error(
+ "--nowipe not set thus deleting the work directory. If you "
+ "wish to debug this, re-run the script with change(s) "
+ "%s and --nowipe by running:\n %s %s %s --nowipe",
+ " ".join(bad_changes),
+ sys.argv[0],
+ " ".join(bad_changes),
+ branch,
+ )
+
+ # Suppress the stack trace if we're not debugging.
+ if options.debug:
+ raise
+ else:
+ return 1
+
+ finally:
+ if options.wipe:
+ shutil.rmtree(root_work_dir)
+
+ if options.dryrun:
+ logging.notice(
+ "Success! To actually upload changes, re-run without " "--dry-run."
+ )
else:
- return 1
+ logging.notice("Successfully uploaded all changes requested.")
- finally:
- if options.wipe:
- shutil.rmtree(root_work_dir)
-
- if options.dryrun:
- logging.notice('Success! To actually upload changes, re-run without '
- '--dry-run.')
- else:
- logging.notice('Successfully uploaded all changes requested.')
-
- return 0
+ return 0