This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new 3cd145b  Use the storage interface for more KEYS functionality
3cd145b is described below

commit 3cd145b04c94c5aefe6ae024c76b66728f1d15a7
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue Jul 22 17:18:21 2025 +0100

    Use the storage interface for more KEYS functionality
---
 atr/blueprints/api/api.py   |  3 +++
 atr/routes/keys.py          | 18 ++++++++----------
 atr/storage/writers/keys.py | 34 ++++++++++++++++++++--------------
 3 files changed, 31 insertions(+), 24 deletions(-)

diff --git a/atr/blueprints/api/api.py b/atr/blueprints/api/api.py
index 2a9c8ae..967a14c 100644
--- a/atr/blueprints/api/api.py
+++ b/atr/blueprints/api/api.py
@@ -391,6 +391,9 @@ async def keys_upload(data: models.api.KeysUploadArgs) -> 
DictResponse:
         outcomes: types.Outcomes[types.Key] = await 
wacm.keys.ensure_associated(filetext)
 
         # TODO: It would be nice to serialise the actual outcomes
+        # Or, perhaps better yet, to have a standard datatype mapping
+        # This would be specified in models.api, then imported into 
storage.types
+        # Or perhaps it should go in models.storage or models.outcomes
         api_outcomes = []
         for outcome in outcomes.outcomes():
             api_outcome: models.api.KeysUploadOutcome | None = None
diff --git a/atr/routes/keys.py b/atr/routes/keys.py
index 83597d8..5b92999 100644
--- a/atr/routes/keys.py
+++ b/atr/routes/keys.py
@@ -40,7 +40,6 @@ import werkzeug.wrappers.response as response
 import wtforms
 
 import atr.db as db
-import atr.db.interaction as interaction
 import atr.models.sql as sql
 import atr.revision as revision
 import atr.routes as routes
@@ -355,17 +354,16 @@ async def import_selected_revision(
         keys_text = await f.read()
     if release.committee is None:
         raise routes.FlashError("No committee found for release")
-    selected_committees = [release.committee.name]
-    try:
-        _upload_results, success_count, error_count, submitted_committees = 
await interaction.upload_keys(
-            session.committees + session.projects, keys_text, 
selected_committees
-        )
-    except interaction.InteractionError as e:
-        return await session.redirect(compose.selected, error=str(e))
-    await autogenerate_keys_file(release.committee.name, 
release.committee.is_podling)
+
+    async with storage.write(session.uid) as write:
+        wacm = 
write.as_committee_member(release.committee.name).result_or_raise()
+        outcomes: types.Outcomes[types.Key] = await 
wacm.keys.ensure_associated(keys_text)
+        success_count = outcomes.result_count
+        error_count = outcomes.exception_count
+
     message = f"Uploaded {success_count} keys,"
     if error_count > 0:
-        message += f" failed to upload {error_count} keys for {', 
'.join(submitted_committees)}"
+        message += f" failed to upload {error_count} keys for 
{release.committee.name}"
     # Remove the KEYS file if 100% imported
     if (success_count > 0) and (error_count == 0):
         description = "Removed KEYS file after successful import through web 
interface"
diff --git a/atr/storage/writers/keys.py b/atr/storage/writers/keys.py
index fdf8d2a..945c281 100644
--- a/atr/storage/writers/keys.py
+++ b/atr/storage/writers/keys.py
@@ -307,20 +307,6 @@ class CommitteeMember(CommitteeParticipant):
         )
 
     @performance_async
-    async def committee(self) -> sql.Committee:
-        return await self.__data.committee(name=self.__committee_name, 
_public_signing_keys=True).demand(
-            storage.AccessError(f"Committee not found: 
{self.__committee_name}")
-        )
-
-    @performance_async
-    async def ensure_associated(self, keys_file_text: str) -> 
types.Outcomes[types.Key]:
-        # TODO: Autogenerate KEYS file
-        return await self.__ensure(keys_file_text, associate=True)
-
-    @performance_async
-    async def ensure_stored(self, keys_file_text: str) -> 
types.Outcomes[types.Key]:
-        return await self.__ensure(keys_file_text, associate=False)
-
     async def autogenerate_keys_file(
         self,
     ) -> types.Outcome[str]:
@@ -352,6 +338,26 @@ class CommitteeMember(CommitteeParticipant):
             return types.OutcomeException(storage.AccessError(error_msg))
         return types.OutcomeResult(str(committee_keys_path))
 
+    @performance_async
+    async def committee(self) -> sql.Committee:
+        return await self.__data.committee(name=self.__committee_name, 
_public_signing_keys=True).demand(
+            storage.AccessError(f"Committee not found: 
{self.__committee_name}")
+        )
+
+    @performance_async
+    async def ensure_associated(self, keys_file_text: str) -> 
types.Outcomes[types.Key]:
+        outcomes: types.Outcomes[types.Key] = await 
self.__ensure(keys_file_text, associate=True)
+        if outcomes.any_ok:
+            await self.autogenerate_keys_file()
+        return outcomes
+
+    @performance_async
+    async def ensure_stored(self, keys_file_text: str) -> 
types.Outcomes[types.Key]:
+        outcomes: types.Outcomes[types.Key] = await 
self.__ensure(keys_file_text, associate=False)
+        if outcomes.any_ok:
+            await self.autogenerate_keys_file()
+        return outcomes
+
     @performance
     def __block_models(self, key_block: str, ldap_data: dict[str, str]) -> 
list[types.Key | Exception]:
         # This cache is only held for the session


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to