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

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


The following commit(s) were added to refs/heads/sbp by this push:
     new 7f5b0c63 Remove the deprecated context manager to create a new revision
7f5b0c63 is described below

commit 7f5b0c632c69349edf9a55e1d016bbb70f50864f
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed Feb 18 17:08:36 2026 +0000

    Remove the deprecated context manager to create a new revision
---
 atr/storage/types.py            |   8 --
 atr/storage/writers/release.py  |  12 +--
 atr/storage/writers/revision.py | 167 +---------------------------------------
 3 files changed, 2 insertions(+), 185 deletions(-)

diff --git a/atr/storage/types.py b/atr/storage/types.py
index 3ed5d423..eb7209a5 100644
--- a/atr/storage/types.py
+++ b/atr/storage/types.py
@@ -99,11 +99,3 @@ class PublicKeyError(Exception):
 
 class FailedError(Exception):
     pass
-
-
[email protected]
-class Creating:
-    old: sql.Revision | None
-    interim_path: pathlib.Path
-    new: sql.Revision | None
-    failed: FailedError | None = None
diff --git a/atr/storage/writers/release.py b/atr/storage/writers/release.py
index 31a78695..7bce2997 100644
--- a/atr/storage/writers/release.py
+++ b/atr/storage/writers/release.py
@@ -20,7 +20,6 @@ from __future__ import annotations
 
 import asyncio
 import base64
-import contextlib
 import datetime
 import hashlib
 from typing import TYPE_CHECKING, Final
@@ -44,7 +43,7 @@ import atr.util as util
 
 if TYPE_CHECKING:
     import pathlib
-    from collections.abc import AsyncGenerator, Sequence
+    from collections.abc import Sequence
 
     import werkzeug.datastructures as datastructures
 
@@ -94,15 +93,6 @@ class CommitteeParticipant(FoundationCommitter):
         self.__asf_uid = asf_uid
         self.__committee_name = committee_name
 
-    @contextlib.asynccontextmanager
-    async def create_and_manage_revision(
-        self, project_name: str, version: str, description: str
-    ) -> AsyncGenerator[types.Creating]:
-        async with self.__write_as.revision.create_and_manage(
-            project_name, version, self.__asf_uid, description=description
-        ) as _creating:
-            yield _creating
-
     async def delete(
         self,
         project_name: str,
diff --git a/atr/storage/writers/revision.py b/atr/storage/writers/revision.py
index 8009853a..4e7f6713 100644
--- a/atr/storage/writers/revision.py
+++ b/atr/storage/writers/revision.py
@@ -41,7 +41,7 @@ import atr.tasks as tasks
 import atr.util as util
 
 if TYPE_CHECKING:
-    from collections.abc import AsyncGenerator, Awaitable, Callable
+    from collections.abc import Awaitable, Callable
 
 
 class SafeSession:
@@ -105,171 +105,6 @@ class CommitteeParticipant(FoundationCommitter):
         self.__asf_uid = asf_uid
         self.__committee_name = committee_name
 
-    @contextlib.asynccontextmanager
-    async def create_and_manage(  # noqa: C901
-        self,
-        project_name: str,
-        version_name: str,
-        asf_uid: str,
-        description: str | None = None,
-        use_check_cache: bool = True,
-    ) -> AsyncGenerator[types.Creating]:
-        """Manage the creation and symlinking of a mutable release revision."""
-        # Get the release
-        release_name = sql.release_name(project_name, version_name)
-        async with db.session() as data:
-            release = await data.release(name=release_name, 
_release_policy=True, _project_release_policy=True).demand(
-                RuntimeError("Release does not exist for new revision 
creation")
-            )
-            old_revision = await interaction.latest_revision(release)
-
-        # Create a temporary directory
-        # We ensure, below, that it's removed on any exception
-        # Use the tmp subdirectory of state, to ensure that it is on the same 
filesystem
-        prefix_token = secrets.token_hex(16)
-        temp_dir: str = await asyncio.to_thread(tempfile.mkdtemp, 
prefix=prefix_token + "-", dir=util.get_tmp_dir())
-        temp_dir_path = pathlib.Path(temp_dir)
-        creating = types.Creating(old=old_revision, 
interim_path=temp_dir_path, new=None, failed=None)
-        try:
-            # The directory was created by mkdtemp, but it's empty
-            if old_revision is not None:
-                # If this is not the first revision, hard link the previous 
revision
-                old_release_dir = util.release_directory(release)
-                await util.create_hard_link_clone(old_release_dir, 
temp_dir_path, do_not_create_dest_dir=True)
-            # The directory is either empty or its files are hard linked to 
the previous revision
-            yield creating
-        except types.FailedError as e:
-            await aioshutil.rmtree(temp_dir)
-            creating.failed = e
-            return
-        except Exception:
-            await aioshutil.rmtree(temp_dir)
-            raise
-
-        validation_errors = await 
asyncio.to_thread(detection.validate_directory, temp_dir_path)
-        if validation_errors:
-            await aioshutil.rmtree(temp_dir)
-            creating.failed = types.FailedError("File validation failed:\n" + 
"\n".join(validation_errors))
-            return
-
-        # Ensure that the permissions of every directory are 755
-        try:
-            await asyncio.to_thread(util.chmod_directories, temp_dir_path)
-        except Exception:
-            await aioshutil.rmtree(temp_dir)
-            raise
-
-        # Make files read only to prevent them from being modified through 
hard links
-        try:
-            await asyncio.to_thread(util.chmod_files, temp_dir_path, 0o444)
-        except Exception:
-            await aioshutil.rmtree(temp_dir)
-            raise
-
-        try:
-            path_to_hash, path_to_size = await 
attestable.paths_to_hashes_and_sizes(temp_dir_path)
-            parent_revision_number = old_revision.number if old_revision else 
None
-            previous_attestable = None
-            if parent_revision_number is not None:
-                previous_attestable = await attestable.load(project_name, 
version_name, parent_revision_number)
-            base_inodes: dict[str, int] = {}
-            base_hashes: dict[str, str] = {}
-            if old_revision is not None:
-                base_dir = util.release_directory(release)
-                base_inodes = await asyncio.to_thread(util.paths_to_inodes, 
base_dir)
-                base_hashes = dict(previous_attestable.paths) if 
(previous_attestable is not None) else {}
-            n_inodes = await asyncio.to_thread(util.paths_to_inodes, 
temp_dir_path)
-        except Exception:
-            await aioshutil.rmtree(temp_dir)
-            raise
-
-        async with SafeSession(temp_dir) as data:
-            try:
-                # This is the only place where models.Revision is constructed
-                # That makes models.populate_revision_sequence_and_name safe 
against races
-                # Because that event is called when data.add is called below
-                # And we have a write lock at that point through the use of 
data.begin_immediate
-                new_revision = sql.Revision(
-                    release_name=release_name,
-                    release=release,
-                    asfuid=asf_uid,
-                    created=datetime.datetime.now(datetime.UTC),
-                    phase=release.phase,
-                    description=description,
-                    use_check_cache=use_check_cache,
-                )
-
-                # Acquire the write lock and add the row
-                # We need this write lock for moving the directory below 
atomically
-                # But it also helps to make 
models.populate_revision_sequence_and_name safe against races
-                await data.begin_immediate()
-                data.add(new_revision)
-
-                # Flush but do not commit the new revision row to get its name 
and number
-                # The row will still be invisible to other sessions after 
flushing
-                await data.flush()
-                # Give the caller details about the new revision
-                creating.new = new_revision
-
-                # Merge with the prior revision if there was an intervening 
change
-                prior_name = new_revision.parent_name
-                if (old_revision is not None) and (prior_name is not None) and 
(prior_name != old_revision.name):
-                    prior_number = prior_name.split()[-1]
-                    prior_dir = util.release_directory_base(release) / 
prior_number
-                    await merge.merge(
-                        base_inodes,
-                        base_hashes,
-                        prior_dir,
-                        project_name,
-                        version_name,
-                        prior_number,
-                        temp_dir_path,
-                        n_inodes,
-                        path_to_hash,
-                        path_to_size,
-                    )
-                    previous_attestable = await attestable.load(project_name, 
version_name, prior_number)
-
-                # Rename the directory to the new revision number
-                await data.refresh(release)
-                new_revision_dir = util.release_directory(release)
-
-                # Ensure that the parent directory exists
-                await aiofiles.os.makedirs(new_revision_dir.parent, 
exist_ok=True)
-
-                # Rename the temporary interim directory to the new revision 
number
-                await aiofiles.os.rename(temp_dir, new_revision_dir)
-            except Exception:
-                await aioshutil.rmtree(temp_dir)
-                raise
-
-            policy = release.release_policy or release.project.release_policy
-
-            await attestable.write_files_data(
-                project_name,
-                version_name,
-                new_revision.number,
-                policy.model_dump() if policy else None,
-                asf_uid,
-                previous_attestable,
-                path_to_hash,
-                path_to_size,
-            )
-
-            # Commit to end the transaction started by data.begin_immediate
-            # We must commit the revision before starting the checks
-            # This also releases the write lock
-            await data.commit()
-
-            async with data.begin():
-                # Run checks if in DRAFT phase
-                # We could also run this outside the data Session
-                # But then it would create its own new Session
-                # It does, however, need a transaction to be created using 
data.begin()
-                if release.phase == sql.ReleasePhase.RELEASE_CANDIDATE_DRAFT:
-                    # Must use caller_data here because we acquired the write 
lock
-                    await tasks.draft_checks(asf_uid, project_name, 
version_name, new_revision.number, caller_data=data)
-
     async def create_revision(  # noqa: C901
         self,
         project_name: str,


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

Reply via email to