diff --git a/project.py b/project.py index 1821c354..40ca116d 100644 --- a/project.py +++ b/project.py @@ -21,6 +21,7 @@ import random import re import shutil import stat +import string import subprocess import sys import tarfile @@ -266,6 +267,7 @@ class ReviewableBranch: dest_branch=None, validate_certs=True, push_options=None, + patchset_description=None, ): self.project.UploadForReview( branch=self.name, @@ -281,6 +283,7 @@ class ReviewableBranch: dest_branch=dest_branch, validate_certs=validate_certs, push_options=push_options, + patchset_description=patchset_description, ) def GetPublishedRefs(self): @@ -1089,6 +1092,7 @@ class Project: dest_branch=None, validate_certs=True, push_options=None, + patchset_description=None, ): """Uploads the named branch for code review.""" if branch is None: @@ -1171,6 +1175,10 @@ class Project: opts += ["wip"] if ready: opts += ["ready"] + if patchset_description: + opts += [ + f"m={self._encode_patchset_description(patchset_description)}" + ] if opts: ref_spec = ref_spec + "%" + ",".join(opts) cmd.append(ref_spec) @@ -1183,6 +1191,30 @@ class Project: R_PUB + branch.name, R_HEADS + branch.name, message=msg ) + @staticmethod + def _encode_patchset_description(original): + """Applies percent-encoding for strings sent as patchset description. + + The encoding used is based on but stricter than URL encoding (Section + 2.1 of RFC 3986). The only non-escaped characters are alphanumerics, and + 'SPACE' (U+0020) can be represented as 'LOW LINE' (U+005F) or + 'PLUS SIGN' (U+002B). + + For more information, see the Gerrit docs here: + https://gerrit-review.googlesource.com/Documentation/user-upload.html#patch_set_description + """ + SAFE = {ord(x) for x in string.ascii_letters + string.digits} + + def _enc(b): + if b in SAFE: + return chr(b) + elif b == ord(" "): + return "_" + else: + return f"%{b:02x}" + + return "".join(_enc(x) for x in original.encode("utf-8")) + def _ExtractArchive(self, tarpath, path=None): """Extract the given tar on its current location diff --git a/subcmds/upload.py b/subcmds/upload.py index 4bcdfaf9..001453fe 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py @@ -244,6 +244,11 @@ Gerrit Code Review: https://www.gerritcodereview.com/ default=[], help="add a label when uploading", ) + p.add_option( + "--pd", + "--patchset-description", + help="description for patchset", + ) p.add_option( "--re", "--reviewers", @@ -655,6 +660,7 @@ Gerrit Code Review: https://www.gerritcodereview.com/ dest_branch=destination, validate_certs=opt.validate_certs, push_options=opt.push_options, + patchset_description=opt.patchset_description, ) branch.uploaded = True diff --git a/tests/test_project.py b/tests/test_project.py index 6dc071bd..de26e91a 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -107,6 +107,16 @@ class ReviewableBranchTests(unittest.TestCase): self.assertTrue(rb.date) +class ProjectTests(unittest.TestCase): + """Check Project behavior.""" + + def test_encode_patchset_description(self): + self.assertEqual( + project.Project._encode_patchset_description("abcd00!! +"), + "abcd00%21%21_%2b", + ) + + class CopyLinkTestCase(unittest.TestCase): """TestCase for stub repo client checkouts.