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 6b005a3  Move the code to remove RC tags to the release writer
6b005a3 is described below

commit 6b005a3e54626279959b45da7fcb940156d9a9f4
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Sep 11 20:18:10 2025 +0100

    Move the code to remove RC tags to the release writer
---
 atr/routes/finish.py           | 98 +++---------------------------------------
 atr/storage/writers/release.py | 89 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 96 insertions(+), 91 deletions(-)

diff --git a/atr/routes/finish.py b/atr/routes/finish.py
index 4e658a6..33c373f 100644
--- a/atr/routes/finish.py
+++ b/atr/routes/finish.py
@@ -34,7 +34,6 @@ import atr.db as db
 import atr.forms as forms
 import atr.log as log
 import atr.models.sql as sql
-import atr.revision as revision
 import atr.routes as routes
 import atr.routes.mapping as mapping
 import atr.routes.root as root
@@ -225,16 +224,6 @@ async def _analyse_rc_tags(latest_revision_dir: 
pathlib.Path) -> RCTagAnalysisRe
     return r
 
 
-async def _current_paths(creating: revision.Creating) -> list[pathlib.Path]:
-    all_current_paths_interim: list[pathlib.Path] = []
-    async for p_rel_interim in util.paths_recursive_all(creating.interim_path):
-        all_current_paths_interim.append(p_rel_interim)
-
-    # This manner of sorting is necessary to ensure that directories are 
removed after their contents
-    all_current_paths_interim.sort(key=lambda p: (-len(p.parts), str(p)))
-    return all_current_paths_interim
-
-
 async def _deletable_choices(latest_revision_dir: pathlib.Path, target_dirs: 
set[pathlib.Path]) -> Any:
     # This should be -> list[tuple[str, str]], but that causes pyright to 
complain incorrectly
     # Details in 
pyright/dist/dist/typeshed-fallback/stubs/WTForms/wtforms/fields/choices.pyi
@@ -323,17 +312,15 @@ async def _remove_rc_tags(
     version_name: str,
     respond: Respond,
 ) -> tuple[quart_response.Response, int] | response.Response:
-    description = "Remove RC tags from paths via web interface"
-    error_messages: list[str] = []
-
     try:
-        async with revision.create_and_manage(
-            project_name, version_name, session.uid, description=description
-        ) as creating:
-            renamed_count = await _remove_rc_tags_revision(creating, 
error_messages)
+        async with storage.write(session.uid) as write:
+            wacp = await write.as_project_committee_member(project_name)
+            creation_error, renamed_count, error_messages = await 
wacp.release.remove_rc_tags(
+                project_name, version_name
+            )
 
-        if creating.failed is not None:
-            return await respond(409, str(creating.failed))
+        if creation_error is not None:
+            return await respond(409, creation_error)
 
         if error_messages:
             status_ok = renamed_count > 0
@@ -351,77 +338,6 @@ async def _remove_rc_tags(
         return await respond(500, f"Unexpected error: {e!s}")
 
 
-async def _remove_rc_tags_revision(
-    creating: revision.Creating,
-    error_messages: list[str],
-) -> int:
-    all_current_paths_interim = await _current_paths(creating)
-    renamed_count_local = 0
-    for path_rel_original_interim in all_current_paths_interim:
-        path_rel_stripped_interim = 
analysis.candidate_removed(path_rel_original_interim)
-
-        if path_rel_original_interim != path_rel_stripped_interim:
-            # Absolute paths of the source and destination
-            full_original_path = creating.interim_path / 
path_rel_original_interim
-            full_stripped_path = creating.interim_path / 
path_rel_stripped_interim
-
-            skip, renamed_count_local = await _remove_rc_tags_revision_item(
-                path_rel_original_interim,
-                full_original_path,
-                full_stripped_path,
-                error_messages,
-                renamed_count_local,
-            )
-            if skip:
-                continue
-
-            try:
-                if not await 
aiofiles.os.path.exists(full_stripped_path.parent):
-                    # This could happen if e.g. a file is in an RC tagged 
directory
-                    # TODO: Move to the storage interface
-                    await aiofiles.os.makedirs(full_stripped_path.parent, 
exist_ok=True)
-
-                if await aiofiles.os.path.exists(full_stripped_path):
-                    error_messages.append(
-                        f"Skipped '{path_rel_original_interim}': target 
'{path_rel_stripped_interim}' already exists."
-                    )
-                    continue
-
-                # TODO: Move to the storage interface
-                await aiofiles.os.rename(full_original_path, 
full_stripped_path)
-                renamed_count_local += 1
-            except Exception as e:
-                error_messages.append(f"Error renaming 
'{path_rel_original_interim}': {e}")
-    return renamed_count_local
-
-
-async def _remove_rc_tags_revision_item(
-    path_rel_original_interim: pathlib.Path,
-    full_original_path: pathlib.Path,
-    full_stripped_path: pathlib.Path,
-    error_messages: list[str],
-    renamed_count_local: int,
-) -> tuple[bool, int]:
-    if await aiofiles.os.path.isdir(full_original_path):
-        # If moving an RC tagged directory to an existing directory...
-        is_target_dir_and_exists = await 
aiofiles.os.path.isdir(full_stripped_path)
-        if is_target_dir_and_exists and (full_stripped_path != 
full_original_path):
-            try:
-                # And the source directory is empty...
-                if not await aiofiles.os.listdir(full_original_path):
-                    # This means we probably moved files out of the RC tagged 
directory
-                    # In any case, we can't move it, so we have to delete it
-                    # TODO: Move to the storage interface
-                    await aiofiles.os.rmdir(full_original_path)
-                    renamed_count_local += 1
-                else:
-                    error_messages.append(f"Source RC directory 
'{path_rel_original_interim}' is not empty, skipping.")
-            except OSError as e:
-                error_messages.append(f"Error removing source RC directory 
'{path_rel_original_interim}': {e}")
-            return True, renamed_count_local
-    return False, renamed_count_local
-
-
 async def _sources_and_targets(latest_revision_dir: pathlib.Path) -> 
tuple[list[pathlib.Path], set[pathlib.Path]]:
     source_items_rel: list[pathlib.Path] = []
     target_dirs: set[pathlib.Path] = {pathlib.Path(".")}
diff --git a/atr/storage/writers/release.py b/atr/storage/writers/release.py
index f49c95c..2db97e5 100644
--- a/atr/storage/writers/release.py
+++ b/atr/storage/writers/release.py
@@ -182,6 +182,15 @@ class CommitteeParticipant(FoundationCommitter):
         creation_error = str(creating.failed) if (creating.failed is not None) 
else None
         return creation_error, moved_files_names, skipped_files_names
 
+    async def remove_rc_tags(self, project_name: str, version_name: str) -> 
tuple[str | None, int, list[str]]:
+        description = "Remove RC tags from paths via web interface"
+        error_messages: list[str] = []
+
+        async with self.create_and_manage_revision(project_name, version_name, 
description) as creating:
+            renamed_count = await self.__remove_rc_tags_revision(creating, 
error_messages)
+        creation_error = str(creating.failed) if (creating.failed is not None) 
else None
+        return creation_error, renamed_count, error_messages
+
     async def start(self, project_name: str, version: str) -> 
tuple[sql.Release, sql.Project]:
         """Creates the initial release draft record and revision directory."""
         # Get the project from the project name
@@ -258,6 +267,15 @@ class CommitteeParticipant(FoundationCommitter):
                 number=creating.new.number,
             ).demand(storage.AccessError("Revision not found"))
 
+    async def __current_paths(self, creating: revision.Creating) -> 
list[pathlib.Path]:
+        all_current_paths_interim: list[pathlib.Path] = []
+        async for p_rel_interim in 
util.paths_recursive_all(creating.interim_path):
+            all_current_paths_interim.append(p_rel_interim)
+
+        # This manner of sorting is necessary to ensure that directories are 
removed after their contents
+        all_current_paths_interim.sort(key=lambda p: (-len(p.parts), str(p)))
+        return all_current_paths_interim
+
     def __related_files(self, path: pathlib.Path) -> list[pathlib.Path]:
         base_path = path.with_suffix("") if (path.suffix in SPECIAL_SUFFIXES) 
else path
         parent_dir = base_path.parent
@@ -269,6 +287,77 @@ class CommitteeParticipant(FoundationCommitter):
             parent_dir / f"{name_without_ext}.sha512",
         ]
 
+    async def __remove_rc_tags_revision(
+        self,
+        creating: revision.Creating,
+        error_messages: list[str],
+    ) -> int:
+        all_current_paths_interim = await self.__current_paths(creating)
+        renamed_count_local = 0
+        for path_rel_original_interim in all_current_paths_interim:
+            path_rel_stripped_interim = 
analysis.candidate_removed(path_rel_original_interim)
+
+            if path_rel_original_interim != path_rel_stripped_interim:
+                # Absolute paths of the source and destination
+                full_original_path = creating.interim_path / 
path_rel_original_interim
+                full_stripped_path = creating.interim_path / 
path_rel_stripped_interim
+
+                skip, renamed_count_local = await 
self.__remove_rc_tags_revision_item(
+                    path_rel_original_interim,
+                    full_original_path,
+                    full_stripped_path,
+                    error_messages,
+                    renamed_count_local,
+                )
+                if skip:
+                    continue
+
+                try:
+                    if not await 
aiofiles.os.path.exists(full_stripped_path.parent):
+                        # This could happen if e.g. a file is in an RC tagged 
directory
+                        await aiofiles.os.makedirs(full_stripped_path.parent, 
exist_ok=True)
+
+                    if await aiofiles.os.path.exists(full_stripped_path):
+                        error_messages.append(
+                            f"Skipped '{path_rel_original_interim}':"
+                            f" target '{path_rel_stripped_interim}' already 
exists."
+                        )
+                        continue
+
+                    await aiofiles.os.rename(full_original_path, 
full_stripped_path)
+                    renamed_count_local += 1
+                except Exception as e:
+                    error_messages.append(f"Error renaming 
'{path_rel_original_interim}': {e}")
+        return renamed_count_local
+
+    async def __remove_rc_tags_revision_item(
+        self,
+        path_rel_original_interim: pathlib.Path,
+        full_original_path: pathlib.Path,
+        full_stripped_path: pathlib.Path,
+        error_messages: list[str],
+        renamed_count_local: int,
+    ) -> tuple[bool, int]:
+        if await aiofiles.os.path.isdir(full_original_path):
+            # If moving an RC tagged directory to an existing directory...
+            is_target_dir_and_exists = await 
aiofiles.os.path.isdir(full_stripped_path)
+            if is_target_dir_and_exists and (full_stripped_path != 
full_original_path):
+                try:
+                    # And the source directory is empty...
+                    if not await aiofiles.os.listdir(full_original_path):
+                        # This means we probably moved files out of the RC 
tagged directory
+                        # In any case, we can't move it, so we have to delete 
it
+                        await aiofiles.os.rmdir(full_original_path)
+                        renamed_count_local += 1
+                    else:
+                        error_messages.append(
+                            f"Source RC directory 
'{path_rel_original_interim}' is not empty, skipping."
+                        )
+                except OSError as e:
+                    error_messages.append(f"Error removing source RC directory 
'{path_rel_original_interim}': {e}")
+                return True, renamed_count_local
+        return False, renamed_count_local
+
     async def __setup_revision(
         self,
         source_files_rel: list[pathlib.Path],


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

Reply via email to