You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by sb...@apache.org on 2026/08/11 13:44:00 UTC
(tooling-trusted-releases) branch sbp updated: Update release validation to not use the finished directory
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 56188426 Update release validation to not use the finished directory
56188426 is described below
commit 5618842662297b86e8e3d6fabab3d7e1d1e26405
Author: Sean B. Palmer <se...@miscoranda.com>
AuthorDate: Tue Aug 11 14:43:29 2026 +0100
Update release validation to not use the finished directory
---
atr/admin/__init__.py | 17 +++++++---
atr/validate.py | 5 +++
tests/unit/test_admin_consistency.py | 49 +++++++++++++++++++++++++++
tests/unit/test_validate_on_disk.py | 65 ++++++++++++++++++++++++++++++++++++
4 files changed, 131 insertions(+), 5 deletions(-)
diff --git a/atr/admin/__init__.py b/atr/admin/__init__.py
index 37f08f62..3f31439f 100644
--- a/atr/admin/__init__.py
+++ b/atr/admin/__init__.py
@@ -27,7 +27,7 @@ import pathlib
import statistics
import sys
import time
-from collections.abc import Callable, Mapping
+from collections.abc import Callable, Mapping, Sequence
from typing import Annotated, Any, Final, Literal, NamedTuple
import aiofiles.os
@@ -1364,10 +1364,7 @@ async def consistency(_session: web.Committer, _consistency: Literal["consistenc
# Get all releases from the database
async with db.session() as data:
releases = await data.release().all()
- database_dirs = []
- for release in releases:
- path = paths.release_directory_version(release)
- database_dirs.append(str(path))
+ database_dirs = await _consistency_database_dirs(releases)
if len(set(database_dirs)) != len(database_dirs):
raise base.ASFQuartException("Duplicate release directories in database", errorcode=500)
@@ -2690,6 +2687,16 @@ def _format_exception_location(exc: BaseException) -> str:
return f"{type(exc).__name__} at {filename}:{lineno} in {func}: {exc}"
+async def _consistency_database_dirs(releases: Sequence[sql.Release]) -> list[str]:
+ database_dirs: list[str] = []
+ for release in releases:
+ path = paths.release_directory_version(release)
+ if (release.phase == sql.ReleasePhase.RELEASE) and (not await aiofiles.os.path.isdir(path)):
+ continue
+ database_dirs.append(str(path))
+ return database_dirs
+
+
async def _get_filesystem_dirs() -> list[str]:
filesystem_dirs = []
await _get_filesystem_dirs_finished(filesystem_dirs)
diff --git a/atr/validate.py b/atr/validate.py
index 6c09c80b..813ad067 100644
--- a/atr/validate.py
+++ b/atr/validate.py
@@ -452,6 +452,11 @@ def release_key(r: sql.Release) -> Divergences:
@release_components("Release")
def release_on_disk(r: sql.Release) -> Divergences:
"""Check that the release is on disk."""
+ if r.phase == sql.ReleasePhase.RELEASE:
+ unfinished = paths.get_unfinished_dir() / r.project_key / r.version
+ expected = "no unfinished directory to remain after release"
+ yield from divergences_predicate(lambda p: not p.path.exists(), expected, unfinished)
+ return
path = paths.release_directory(r)
def okay(p: safe.StatePath) -> bool:
diff --git a/tests/unit/test_admin_consistency.py b/tests/unit/test_admin_consistency.py
new file mode 100644
index 00000000..d49fbccf
--- /dev/null
+++ b/tests/unit/test_admin_consistency.py
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import pathlib
+import unittest.mock as mock
+
+import pytest
+
+import atr.admin as admin
+import atr.config as config
+import atr.models.sql as sql
+
+
+def release(phase: sql.ReleasePhase, project_key: str, version: str) -> mock.MagicMock:
+ result = mock.MagicMock()
+ result.phase = phase
+ result.project_key = project_key
+ result.version = version
+ return result
+
+
+async def test_consistency_database_dirs(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> None:
+ monkeypatch.setattr(config.get(), "FINISHED_STORAGE_DIR", str(tmp_path / "finished"), raising=False)
+ monkeypatch.setattr(config.get(), "UNFINISHED_STORAGE_DIR", str(tmp_path / "unfinished"), raising=False)
+ (tmp_path / "finished" / "old" / "1.0").mkdir(parents=True)
+ old_world = release(sql.ReleasePhase.RELEASE, "old", "1.0")
+ new_world = release(sql.ReleasePhase.RELEASE, "newer", "2.0")
+ draft = release(sql.ReleasePhase.RELEASE_CANDIDATE_DRAFT, "draft", "3.0")
+
+ dirs = await admin._consistency_database_dirs([old_world, new_world, draft])
+
+ assert dirs == [
+ str(tmp_path / "finished" / "old" / "1.0"),
+ str(tmp_path / "unfinished" / "draft" / "3.0"),
+ ]
diff --git a/tests/unit/test_validate_on_disk.py b/tests/unit/test_validate_on_disk.py
new file mode 100644
index 00000000..079dab12
--- /dev/null
+++ b/tests/unit/test_validate_on_disk.py
@@ -0,0 +1,65 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import pathlib
+import unittest.mock as mock
+
+import pytest
+
+import atr.models.safe as safe
+import atr.models.sql as sql
+import atr.validate as validate
+
+
+def release(phase: sql.ReleasePhase) -> mock.MagicMock:
+ result = mock.MagicMock()
+ result.phase = phase
+ result.key = "proj-1.0"
+ result.project_key = "proj"
+ result.version = "1.0"
+ return result
+
+
+def test_release_on_disk_flags_lingering_unfinished_directory(
+ tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
+) -> None:
+ (tmp_path / "unfinished" / "proj" / "1.0").mkdir(parents=True)
+ monkeypatch.setattr(validate.paths, "get_unfinished_dir", lambda: safe.StatePath(tmp_path / "unfinished"))
+
+ divergences = list(validate.release_on_disk(release(sql.ReleasePhase.RELEASE)))
+
+ assert len(divergences) == 1
+
+
+def test_release_on_disk_flags_missing_draft_directory(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> None:
+ monkeypatch.setattr(
+ validate.paths, "release_directory", lambda _release: safe.StatePath(tmp_path / "unfinished" / "proj" / "1.0")
+ )
+
+ divergences = list(validate.release_on_disk(release(sql.ReleasePhase.RELEASE_CANDIDATE_DRAFT)))
+
+ assert len(divergences) == 1
+
+
+def test_release_on_disk_passes_released_without_directories(
+ tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
+) -> None:
+ monkeypatch.setattr(validate.paths, "get_unfinished_dir", lambda: safe.StatePath(tmp_path / "unfinished"))
+
+ divergences = list(validate.release_on_disk(release(sql.ReleasePhase.RELEASE)))
+
+ assert divergences == []
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org