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 838e9a65 Add a table for release file states to the database
838e9a65 is described below

commit 838e9a65240dc525269336137efcb9e71521526d
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Mar 16 18:45:09 2026 +0000

    Add a table for release file states to the database
---
 atr/db/__init__.py                              | 26 +++++++++++++
 atr/models/sql.py                               | 28 ++++++++++++++
 migrations/versions/0059_2026.03.16_7dda4775.py | 50 +++++++++++++++++++++++++
 3 files changed, 104 insertions(+)

diff --git a/atr/db/__init__.py b/atr/db/__init__.py
index 3236e117..83011f38 100644
--- a/atr/db/__init__.py
+++ b/atr/db/__init__.py
@@ -566,6 +566,32 @@ class Session(sqlalchemy.ext.asyncio.AsyncSession):
 
         return Query(self, query)
 
+    def release_file_state(
+        self,
+        release_name: Opt[str] = NOT_SET,
+        path: Opt[str] = NOT_SET,
+        since_revision_seq: Opt[int] = NOT_SET,
+        present: Opt[bool] = NOT_SET,
+        content_hash: Opt[str | None] = NOT_SET,
+        classification: Opt[str | None] = NOT_SET,
+    ) -> Query[sql.ReleaseFileState]:
+        query = sqlmodel.select(sql.ReleaseFileState)
+
+        if is_defined(release_name):
+            query = query.where(sql.ReleaseFileState.release_name == 
release_name)
+        if is_defined(path):
+            query = query.where(sql.ReleaseFileState.path == path)
+        if is_defined(since_revision_seq):
+            query = query.where(sql.ReleaseFileState.since_revision_seq == 
since_revision_seq)
+        if is_defined(present):
+            query = query.where(sql.ReleaseFileState.present == present)
+        if is_defined(content_hash):
+            query = query.where(sql.ReleaseFileState.content_hash == 
content_hash)
+        if is_defined(classification):
+            query = query.where(sql.ReleaseFileState.classification == 
classification)
+
+        return Query(self, query)
+
     def release_policy(
         self,
         id: Opt[int] = NOT_SET,
diff --git a/atr/models/sql.py b/atr/models/sql.py
index 7b24582f..d583b363 100644
--- a/atr/models/sql.py
+++ b/atr/models/sql.py
@@ -1226,6 +1226,34 @@ class Quarantined(sqlmodel.SQLModel, table=True):
             self.status = QuarantineStatus(self.status)
 
 
+# ReleaseFileState: Revision
+class ReleaseFileState(sqlmodel.SQLModel, table=True):
+    release_name: str = sqlmodel.Field(primary_key=True, 
**example("example-0.0.1"))
+    path: str = sqlmodel.Field(primary_key=True, 
**example("apache-example-0.0.1-src.tar.gz"))
+    since_revision_seq: int = sqlmodel.Field(primary_key=True, **example(1))
+    present: bool = sqlmodel.Field(**example(True))
+    content_hash: str | None = sqlmodel.Field(default=None, 
**example("blake3:7f83b1657ff1fc..."))
+    classification: str | None = sqlmodel.Field(default=None, 
**example("source"))
+
+    __table_args__ = (
+        sqlalchemy.ForeignKeyConstraint(
+            ["release_name", "since_revision_seq"],
+            ["revision.release_name", "revision.seq"],
+            ondelete="CASCADE",
+        ),
+        sqlalchemy.CheckConstraint(
+            """
+            (
+                (present = 1 AND content_hash IS NOT NULL AND classification 
IS NOT NULL)
+                OR
+                (present = 0 AND content_hash IS NULL AND classification IS 
NULL)
+            )
+            """,
+            name="valid_release_file_state",
+        ),
+    )
+
+
 # ReleasePolicy: Project
 class ReleasePolicy(sqlmodel.SQLModel, table=True):
     id: int = sqlmodel.Field(default=None, primary_key=True)
diff --git a/migrations/versions/0059_2026.03.16_7dda4775.py 
b/migrations/versions/0059_2026.03.16_7dda4775.py
new file mode 100644
index 00000000..73dea89e
--- /dev/null
+++ b/migrations/versions/0059_2026.03.16_7dda4775.py
@@ -0,0 +1,50 @@
+"""Add release file state data
+
+Revision ID: 0059_2026.03.16_7dda4775
+Revises: 0058_2026.03.12_2ebee77e
+Create Date: 2026-03-16 17:10:20.840574+00:00
+"""
+
+from collections.abc import Sequence
+
+import sqlalchemy as sa
+from alembic import op
+
+# Revision identifiers, used by Alembic
+revision: str = "0059_2026.03.16_7dda4775"
+down_revision: str | None = "0058_2026.03.12_2ebee77e"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
+
+
+def upgrade() -> None:
+    op.create_table(
+        "releasefilestate",
+        sa.Column("release_name", sa.String(), nullable=False),
+        sa.Column("path", sa.String(), nullable=False),
+        sa.Column("since_revision_seq", sa.Integer(), nullable=False),
+        sa.Column("present", sa.Boolean(), nullable=False),
+        sa.Column("content_hash", sa.String(), nullable=True),
+        sa.Column("classification", sa.String(), nullable=True),
+        sa.ForeignKeyConstraint(
+            ["release_name", "since_revision_seq"],
+            ["revision.release_name", "revision.seq"],
+            
name=op.f("fk_releasefilestate_release_name_since_revision_seq_revision"),
+            ondelete="CASCADE",
+        ),
+        sa.PrimaryKeyConstraint("release_name", "path", "since_revision_seq", 
name=op.f("pk_releasefilestate")),
+        sa.CheckConstraint(
+            """
+            (
+                (present = 1 AND content_hash IS NOT NULL AND classification 
IS NOT NULL)
+                OR
+                (present = 0 AND content_hash IS NULL AND classification IS 
NULL)
+            )
+            """,
+            name=op.f("ck_releasefilestate_valid_release_file_state"),
+        ),
+    )
+
+
+def downgrade() -> None:
+    op.drop_table("releasefilestate")


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

Reply via email to