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]