diff options
| -rw-r--r-- | project.py | 32 | ||||
| -rw-r--r-- | subcmds/upload.py | 6 | ||||
| -rw-r--r-- | tests/test_project.py | 10 |
3 files changed, 48 insertions, 0 deletions
| @@ -21,6 +21,7 @@ import random | |||
| 21 | import re | 21 | import re |
| 22 | import shutil | 22 | import shutil |
| 23 | import stat | 23 | import stat |
| 24 | import string | ||
| 24 | import subprocess | 25 | import subprocess |
| 25 | import sys | 26 | import sys |
| 26 | import tarfile | 27 | import tarfile |
| @@ -266,6 +267,7 @@ class ReviewableBranch: | |||
| 266 | dest_branch=None, | 267 | dest_branch=None, |
| 267 | validate_certs=True, | 268 | validate_certs=True, |
| 268 | push_options=None, | 269 | push_options=None, |
| 270 | patchset_description=None, | ||
| 269 | ): | 271 | ): |
| 270 | self.project.UploadForReview( | 272 | self.project.UploadForReview( |
| 271 | branch=self.name, | 273 | branch=self.name, |
| @@ -281,6 +283,7 @@ class ReviewableBranch: | |||
| 281 | dest_branch=dest_branch, | 283 | dest_branch=dest_branch, |
| 282 | validate_certs=validate_certs, | 284 | validate_certs=validate_certs, |
| 283 | push_options=push_options, | 285 | push_options=push_options, |
| 286 | patchset_description=patchset_description, | ||
| 284 | ) | 287 | ) |
| 285 | 288 | ||
| 286 | def GetPublishedRefs(self): | 289 | def GetPublishedRefs(self): |
| @@ -1089,6 +1092,7 @@ class Project: | |||
| 1089 | dest_branch=None, | 1092 | dest_branch=None, |
| 1090 | validate_certs=True, | 1093 | validate_certs=True, |
| 1091 | push_options=None, | 1094 | push_options=None, |
| 1095 | patchset_description=None, | ||
| 1092 | ): | 1096 | ): |
| 1093 | """Uploads the named branch for code review.""" | 1097 | """Uploads the named branch for code review.""" |
| 1094 | if branch is None: | 1098 | if branch is None: |
| @@ -1171,6 +1175,10 @@ class Project: | |||
| 1171 | opts += ["wip"] | 1175 | opts += ["wip"] |
| 1172 | if ready: | 1176 | if ready: |
| 1173 | opts += ["ready"] | 1177 | opts += ["ready"] |
| 1178 | if patchset_description: | ||
| 1179 | opts += [ | ||
| 1180 | f"m={self._encode_patchset_description(patchset_description)}" | ||
| 1181 | ] | ||
| 1174 | if opts: | 1182 | if opts: |
| 1175 | ref_spec = ref_spec + "%" + ",".join(opts) | 1183 | ref_spec = ref_spec + "%" + ",".join(opts) |
| 1176 | cmd.append(ref_spec) | 1184 | cmd.append(ref_spec) |
| @@ -1183,6 +1191,30 @@ class Project: | |||
| 1183 | R_PUB + branch.name, R_HEADS + branch.name, message=msg | 1191 | R_PUB + branch.name, R_HEADS + branch.name, message=msg |
| 1184 | ) | 1192 | ) |
| 1185 | 1193 | ||
| 1194 | @staticmethod | ||
| 1195 | def _encode_patchset_description(original): | ||
| 1196 | """Applies percent-encoding for strings sent as patchset description. | ||
| 1197 | |||
| 1198 | The encoding used is based on but stricter than URL encoding (Section | ||
| 1199 | 2.1 of RFC 3986). The only non-escaped characters are alphanumerics, and | ||
| 1200 | 'SPACE' (U+0020) can be represented as 'LOW LINE' (U+005F) or | ||
| 1201 | 'PLUS SIGN' (U+002B). | ||
| 1202 | |||
| 1203 | For more information, see the Gerrit docs here: | ||
| 1204 | https://gerrit-review.googlesource.com/Documentation/user-upload.html#patch_set_description | ||
| 1205 | """ | ||
| 1206 | SAFE = {ord(x) for x in string.ascii_letters + string.digits} | ||
| 1207 | |||
| 1208 | def _enc(b): | ||
| 1209 | if b in SAFE: | ||
| 1210 | return chr(b) | ||
| 1211 | elif b == ord(" "): | ||
| 1212 | return "_" | ||
| 1213 | else: | ||
| 1214 | return f"%{b:02x}" | ||
| 1215 | |||
| 1216 | return "".join(_enc(x) for x in original.encode("utf-8")) | ||
| 1217 | |||
| 1186 | def _ExtractArchive(self, tarpath, path=None): | 1218 | def _ExtractArchive(self, tarpath, path=None): |
| 1187 | """Extract the given tar on its current location | 1219 | """Extract the given tar on its current location |
| 1188 | 1220 | ||
diff --git a/subcmds/upload.py b/subcmds/upload.py index 4bcdfaf9..001453fe 100644 --- a/subcmds/upload.py +++ b/subcmds/upload.py | |||
| @@ -245,6 +245,11 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
| 245 | help="add a label when uploading", | 245 | help="add a label when uploading", |
| 246 | ) | 246 | ) |
| 247 | p.add_option( | 247 | p.add_option( |
| 248 | "--pd", | ||
| 249 | "--patchset-description", | ||
| 250 | help="description for patchset", | ||
| 251 | ) | ||
| 252 | p.add_option( | ||
| 248 | "--re", | 253 | "--re", |
| 249 | "--reviewers", | 254 | "--reviewers", |
| 250 | type="string", | 255 | type="string", |
| @@ -655,6 +660,7 @@ Gerrit Code Review: https://www.gerritcodereview.com/ | |||
| 655 | dest_branch=destination, | 660 | dest_branch=destination, |
| 656 | validate_certs=opt.validate_certs, | 661 | validate_certs=opt.validate_certs, |
| 657 | push_options=opt.push_options, | 662 | push_options=opt.push_options, |
| 663 | patchset_description=opt.patchset_description, | ||
| 658 | ) | 664 | ) |
| 659 | 665 | ||
| 660 | branch.uploaded = True | 666 | 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): | |||
| 107 | self.assertTrue(rb.date) | 107 | self.assertTrue(rb.date) |
| 108 | 108 | ||
| 109 | 109 | ||
| 110 | class ProjectTests(unittest.TestCase): | ||
| 111 | """Check Project behavior.""" | ||
| 112 | |||
| 113 | def test_encode_patchset_description(self): | ||
| 114 | self.assertEqual( | ||
| 115 | project.Project._encode_patchset_description("abcd00!! +"), | ||
| 116 | "abcd00%21%21_%2b", | ||
| 117 | ) | ||
| 118 | |||
| 119 | |||
| 110 | class CopyLinkTestCase(unittest.TestCase): | 120 | class CopyLinkTestCase(unittest.TestCase): |
| 111 | """TestCase for stub repo client checkouts. | 121 | """TestCase for stub repo client checkouts. |
| 112 | 122 | ||
