Repository: plone/plone.restapi (language: python)

Issue:
Automatically update version in translated_messages_addons.resp after release.
The version number in `http-examples/translated_messages_addons.resp` must be updated after every release, otherwise the 'no uncommitted changes' test will fail the next time someone runs the tests or makes a PR.

This should be possible with a [`zest.releaser` entry point](https://zestreleaser.readthedocs.io/en/latest/entrypoints.html) specific for `plone.restapi`. An example of such an entry point is in `i18ndude` for updating the output of the command line help in the documentation. The parts are:

- [`setup.py` registration](https://github.com/collective/i18ndude/blob/5.5.0/setup.py#L62-L65)
- [`setup.cfg` registration](https://github.com/collective/i18ndude/blob/5.5.0/setup.cfg#L1-L3)
- [the code for the hook](https://github.com/collective/i18ndude/blob/5.5.0/src/i18ndude/utils.py#L190)

I guess it only needs to be in one of `setup.py` or `setup.cfg`, not both. But it has been a while since I did this, so I am not sure. Having it in `setup.cfg` should mean that you get an error when the hook is for some reason not found. This may or may not be what you want. Having it in `setup.py` should mean it is available globally whenever you release any package, so you need to take care to only have it really do something when releasing `plone.restapi`, but this is an easy check to add.

The best hook would probably be `zest.releaser.postreleaser.middle`.


Discussion / hints:
Example of manual change after release: commit cb63e1ac4aff0570bedba0b88bceb31c34325a88.
The 'test no uncommitted changes' actually [fails](https://github.com/plone/plone.restapi/actions/runs/3495378069/jobs/5852075925) there, but that is for different reasons.
@mauritsvanrees thanks for creating this issue. I was just about to create one. Just for reference I added a comment in the commit that introduced this:

https://github.com/plone/plone.restapi/commit/baa018e65dff1766cf8723b05ef956a107b0ee8f#r90677638

I am wondering if zest.releaser is the way to solve this. We freeze datetime values in the plone.restapi testrunner and I was wondering if we can't monkeypatch the setup.py version during the testrun. I have no clue what's the better way I just wanted to add this as an idea to discuss here...

Fix patch:
diff --git a/news/1538.bugfix b/news/1538.bugfix
new file mode 100644
index 0000000000..c9da7dd2c8
--- /dev/null
+++ b/news/1538.bugfix
@@ -0,0 +1,2 @@
+Mock addon versions in documentation
+[erral]


Test patch:
diff --git a/src/plone/restapi/tests/helpers.py b/src/plone/restapi/tests/helpers.py
index dd01a6d517..3a03dbc0a9 100644
--- a/src/plone/restapi/tests/helpers.py
+++ b/src/plone/restapi/tests/helpers.py
@@ -3,6 +3,7 @@
 from Products.CMFCore.utils import getToolByName
 from unittest.mock import patch
 from urllib.parse import urlparse
+from plone.restapi.services.addons.addons import Addons
 
 import quopri
 
@@ -73,3 +74,14 @@ def patch_scale_uuid(value):
             storage.AnnotationStorage, "_modified_since", return_value=True
         ):
             yield
+
+
+@contextmanager
+def patch_addon_versions(value):
+    """Patch the method that extracts the version of each of the addons.
+    Without this patch we get version errors each time an addon is upgraded
+    which is really annoying when a new version of plone.restapi is released
+    because all PRs need to be updated
+    """
+    with patch.object(Addons, "get_product_version", return_value=value):
+        yield
diff --git a/src/plone/restapi/tests/http-examples/translated_messages_addons.resp b/src/plone/restapi/tests/http-examples/translated_messages_addons.resp
index c486b06c0f..ab08dab007 100644
--- a/src/plone/restapi/tests/http-examples/translated_messages_addons.resp
+++ b/src/plone/restapi/tests/http-examples/translated_messages_addons.resp
@@ -13,7 +13,7 @@ Content-Type: application/json
             "title": "Soporte de Pol\u00edtica de Flujo de trabajo (CMFPlacefulWorkflow)",
             "uninstall_profile_id": "Products.CMFPlacefulWorkflow:uninstall",
             "upgrade_info": {},
-            "version": "3.0.0b2"
+            "version": "1.2.3"
         },
         {
             "@id": "http://localhost:55001/plone/@addons/collective.MockMailHost",
@@ -28,10 +28,10 @@ Content-Type: application/json
                 "available": false,
                 "hasProfile": true,
                 "installedVersion": "2.0.0",
-                "newVersion": "2.0.0",
-                "required": false
+                "newVersion": "1.2.3",
+                "required": true
             },
-            "version": "2.0.0"
+            "version": "1.2.3"
         },
         {
             "@id": "http://localhost:55001/plone/@addons/plone.app.iterate",
@@ -43,7 +43,7 @@ Content-Type: application/json
             "title": "Soporte de Copia de Trabajo (Repetir)",
             "uninstall_profile_id": "plone.app.iterate:uninstall",
             "upgrade_info": {},
-            "version": "4.0.3"
+            "version": "1.2.3"
         },
         {
             "@id": "http://localhost:55001/plone/@addons/plone.app.multilingual",
@@ -55,7 +55,7 @@ Content-Type: application/json
             "title": "Soporte Multiidioma",
             "uninstall_profile_id": "plone.app.multilingual:uninstall",
             "upgrade_info": {},
-            "version": "6.0.0b3"
+            "version": "1.2.3"
         },
         {
             "@id": "http://localhost:55001/plone/@addons/plone.restapi",
@@ -73,7 +73,7 @@ Content-Type: application/json
                 "newVersion": "0006",
                 "required": false
             },
-            "version": "8.32.4.dev0"
+            "version": "1.2.3"
         },
         {
             "@id": "http://localhost:55001/plone/@addons/plone.session",
@@ -85,7 +85,7 @@ Content-Type: application/json
             "title": "Soporte de actualizaci\u00f3n de sesi\u00f3n",
             "uninstall_profile_id": "plone.session:uninstall",
             "upgrade_info": {},
-            "version": "4.0.0b2"
+            "version": "1.2.3"
         }
     ]
 }
diff --git a/src/plone/restapi/tests/test_documentation.py b/src/plone/restapi/tests/test_documentation.py
index 05934d8ec7..9d65353867 100644
--- a/src/plone/restapi/tests/test_documentation.py
+++ b/src/plone/restapi/tests/test_documentation.py
@@ -27,7 +27,7 @@
 from plone.restapi.testing import PLONE_RESTAPI_ITERATE_FUNCTIONAL_TESTING
 from plone.restapi.testing import register_static_uuid_utility
 from plone.restapi.testing import RelativeSession
-from plone.restapi.tests.helpers import patch_scale_uuid
+from plone.restapi.tests.helpers import patch_scale_uuid, patch_addon_versions
 from plone.restapi.tests.statictime import StaticTime
 from plone.testing.z2 import Browser
 from zope.component import createObject
@@ -1371,7 +1371,7 @@ def test_documentation_vocabularies_get_fields(self):
 
     def test_documentation_vocabularies_get_filtered_by_title(self):
         response = self.api_session.get(
-            "/@vocabularies/plone.app.vocabularies.ReallyUserFriendlyTypes?" "title=doc"
+            "/@vocabularies/plone.app.vocabularies.ReallyUserFriendlyTypes?title=doc"
         )
         save_request_and_response_for_docs(
             "vocabularies_get_filtered_by_title", response
@@ -1583,8 +1583,7 @@ def test_locking_lock(self):
         # Replace dynamic lock token with a static one
         response._content = re.sub(
             b'"token": "[^"]+"',
-            b'"token":'
-            b' "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            b'"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
             response.content,
         )
         save_request_and_response_for_docs("lock", response)
@@ -1597,8 +1596,7 @@ def test_locking_lock_nonstealable_and_timeout(self):
         # Replace dynamic lock token with a static one
         response._content = re.sub(
             b'"token": "[^"]+"',
-            b'"token":'
-            b' "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            b'"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
             response.content,
         )
         save_request_and_response_for_docs("lock_nonstealable_timeout", response)
@@ -1624,8 +1622,7 @@ def test_locking_refresh_lock(self):
         # Replace dynamic lock token with a static one
         response._content = re.sub(
             b'"token": "[^"]+"',
-            b'"token":'
-            b' "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
+            b'"token": "0.684672730996-0.25195226375-00105A989226:1477076400.000"',  # noqa
             response.content,
         )
         save_request_and_response_for_docs("refresh_lock", response)
@@ -1741,8 +1738,9 @@ def test_translate_messages_object_history(self):
         )
 
     def test_translate_messages_addons(self):
-        response = self.api_session.get("/@addons")
-        save_request_and_response_for_docs("translated_messages_addons", response)
+        with patch_addon_versions("1.2.3"):
+            response = self.api_session.get("/@addons")
+            save_request_and_response_for_docs("translated_messages_addons", response)
 
 
 class TestCommenting(TestDocumentationBase):