diff --git a/recipes/README.recipes.md b/recipes/README.recipes.md
index 9e0b606a4..393a45c4d 100644
--- a/recipes/README.recipes.md
+++ b/recipes/README.recipes.md
@@ -793,13 +793,13 @@ Returns current gerrit change, if there is exactly one.
Returns a self.m.buildbucket.common_pb2.GerritChange or None.
- **@property**
— **def [gerrit\_change\_fetch\_ref](/recipes/recipe_modules/tryserver/api.py#149)(self):**
+ **@property**
— **def [gerrit\_change\_fetch\_ref](/recipes/recipe_modules/tryserver/api.py#157)(self):**
Returns gerrit patch ref, e.g. "refs/heads/45/12345/6, or None.
Populated iff gerrit_change is populated.
- **@property**
— **def [gerrit\_change\_number](/recipes/recipe_modules/tryserver/api.py#167)(self):**
+ **@property**
— **def [gerrit\_change\_number](/recipes/recipe_modules/tryserver/api.py#175)(self):**
Returns gerrit change patchset, e.g. 12345 for a patch ref of
"refs/heads/45/12345/6".
@@ -831,20 +831,24 @@ Returns canonical URL of the gitiles repo of the current Gerrit CL.
Populated iff gerrit_change is populated.
- **@property**
— **def [gerrit\_change\_target\_ref](/recipes/recipe_modules/tryserver/api.py#158)(self):**
+ **@property**
— **def [gerrit\_change\_review\_url](/recipes/recipe_modules/tryserver/api.py#97)(self):**
+
+Returns the review URL for the active patchset.
+
+ **@property**
— **def [gerrit\_change\_target\_ref](/recipes/recipe_modules/tryserver/api.py#166)(self):**
Returns gerrit change destination ref, e.g. "refs/heads/main".
Populated iff gerrit_change is populated.
- **@property**
— **def [gerrit\_patchset\_number](/recipes/recipe_modules/tryserver/api.py#179)(self):**
+ **@property**
— **def [gerrit\_patchset\_number](/recipes/recipe_modules/tryserver/api.py#187)(self):**
Returns gerrit change patchset, e.g. 6 for a patch ref of
"refs/heads/45/12345/6".
Populated iff gerrit_change is populated Returns None if not populated..
-— **def [get\_files\_affected\_by\_patch](/recipes/recipe_modules/tryserver/api.py#225)(self, patch_root, report_files_via_property=None, \*\*kwargs):**
+— **def [get\_files\_affected\_by\_patch](/recipes/recipe_modules/tryserver/api.py#233)(self, patch_root, report_files_via_property=None, \*\*kwargs):**
Returns list of paths to files affected by the patch.
@@ -856,11 +860,11 @@ Args:
Returned paths will be relative to to api.path['root'].
-— **def [get\_footer](/recipes/recipe_modules/tryserver/api.py#365)(self, tag, patch_text=None):**
+— **def [get\_footer](/recipes/recipe_modules/tryserver/api.py#373)(self, tag, patch_text=None):**
Gets a specific tag from a CL description
-— **def [get\_footers](/recipes/recipe_modules/tryserver/api.py#329)(self, patch_text=None):**
+— **def [get\_footers](/recipes/recipe_modules/tryserver/api.py#337)(self, patch_text=None):**
Retrieves footers from the patch description.
@@ -869,32 +873,32 @@ git-footers documentation for more information.
— **def [initialize](/recipes/recipe_modules/tryserver/api.py#42)(self):**
- **@property**
— **def [is\_gerrit\_issue](/recipes/recipe_modules/tryserver/api.py#196)(self):**
+ **@property**
— **def [is\_gerrit\_issue](/recipes/recipe_modules/tryserver/api.py#204)(self):**
Returns true iff the properties exist to match a Gerrit issue.
- **@property**
— **def [is\_patch\_in\_git](/recipes/recipe_modules/tryserver/api.py#206)(self):**
+ **@property**
— **def [is\_patch\_in\_git](/recipes/recipe_modules/tryserver/api.py#214)(self):**
- **@property**
— **def [is\_tryserver](/recipes/recipe_modules/tryserver/api.py#191)(self):**
+ **@property**
— **def [is\_tryserver](/recipes/recipe_modules/tryserver/api.py#199)(self):**
Returns true iff we have a change to check out.
-— **def [normalize\_footer\_name](/recipes/recipe_modules/tryserver/api.py#373)(self, footer):**
+— **def [normalize\_footer\_name](/recipes/recipe_modules/tryserver/api.py#381)(self, footer):**
-— **def [require\_is\_tryserver](/recipes/recipe_modules/tryserver/api.py#212)(self):**
+— **def [require\_is\_tryserver](/recipes/recipe_modules/tryserver/api.py#220)(self):**
-— **def [set\_change](/recipes/recipe_modules/tryserver/api.py#376)(self, change):**
+— **def [set\_change](/recipes/recipe_modules/tryserver/api.py#384)(self, change):**
Set the gerrit change for this module.
Args:
* change: a self.m.buildbucket.common_pb2.GerritChange.
-— **def [set\_compile\_failure\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#290)(self):**
+— **def [set\_compile\_failure\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#298)(self):**
Mark the tryjob result as a compile failure.
-— **def [set\_invalid\_test\_results\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#302)(self):**
+— **def [set\_invalid\_test\_results\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#310)(self):**
Mark the tryjob result as having invalid test results.
@@ -902,32 +906,32 @@ This means we run some tests, but the results were not valid
(e.g. no list of specific test cases that failed, or too many
tests failing, etc).
-— **def [set\_patch\_failure\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#286)(self):**
+— **def [set\_patch\_failure\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#294)(self):**
Mark the tryjob result as failure to apply the patch.
-— **def [set\_subproject\_tag](/recipes/recipe_modules/tryserver/api.py#264)(self, subproject_tag):**
+— **def [set\_subproject\_tag](/recipes/recipe_modules/tryserver/api.py#272)(self, subproject_tag):**
Adds a subproject tag to the build.
This can be used to distinguish between builds that execute different steps
depending on what was patched, e.g. blink vs. pure chromium patches.
-— **def [set\_test\_expired\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#319)(self):**
+— **def [set\_test\_expired\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#327)(self):**
Mark the tryjob result as a test expiration.
This means a test task expired and was never scheduled, most likely due to
lack of capacity.
-— **def [set\_test\_failure\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#294)(self):**
+— **def [set\_test\_failure\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#302)(self):**
Mark the tryjob result as a test failure.
This means we started running actual tests (not prerequisite steps
like checkout or compile), and some of these tests have failed.
-— **def [set\_test\_timeout\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#311)(self):**
+— **def [set\_test\_timeout\_tryjob\_result](/recipes/recipe_modules/tryserver/api.py#319)(self):**
Mark the tryjob result as a test timeout.
diff --git a/recipes/recipe_modules/tryserver/api.py b/recipes/recipe_modules/tryserver/api.py
index f1cfc4ede..eb587ba41 100644
--- a/recipes/recipe_modules/tryserver/api.py
+++ b/recipes/recipe_modules/tryserver/api.py
@@ -94,6 +94,14 @@ class TryserverApi(recipe_api.RecipeApi):
"""
return self._gerrit_change_owner
+ @property
+ def gerrit_change_review_url(self):
+ """Returns the review URL for the active patchset."""
+ # Gerrit redirects to insert the project into the URL.
+ gerrit_change = self._gerrit_change
+ return 'https://%s/c/%s/%s' % (
+ gerrit_change.host, gerrit_change.change, gerrit_change.patchset)
+
def _ensure_gerrit_change_info(self):
"""Initializes extra info about gerrit_change, fetched from Gerrit server.
diff --git a/recipes/recipe_modules/tryserver/examples/full.py b/recipes/recipe_modules/tryserver/examples/full.py
index e780eb243..fb3624911 100644
--- a/recipes/recipe_modules/tryserver/examples/full.py
+++ b/recipes/recipe_modules/tryserver/examples/full.py
@@ -41,6 +41,8 @@ def RunSteps(api):
expected_target_ref = api.properties.get(
'expected_target_ref', 'refs/heads/main')
assert api.tryserver.gerrit_change_target_ref == expected_target_ref
+ assert (api.tryserver.gerrit_change_review_url ==
+ 'https://chromium-review.googlesource.com/c/91827/1')
if api.tryserver.is_gerrit_issue:
api.tryserver.get_footers()