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-releases-client.git
The following commit(s) were added to refs/heads/main by this push:
new 1ea88bc Use shared models to construct API POST inputs
1ea88bc is described below
commit 1ea88bc10b6313b832d204ebf20874ea0c3e7f12
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Jul 14 19:15:39 2025 +0100
Use shared models to construct API POST inputs
---
pyproject.toml | 4 ++--
src/atrclient/client.py | 48 ++++++++++++++++++++---------------------
src/atrclient/models/api.py | 27 ++++++++++-------------
src/atrclient/models/results.py | 2 --
src/atrclient/models/sql.py | 7 +++---
uv.lock | 4 ++--
6 files changed, 42 insertions(+), 50 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index d40b09e..92faecd 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ build-backend = "hatchling.build"
[project]
name = "apache-trusted-releases"
-version = "0.20250714.1626"
+version = "0.20250714.1815"
description = "ATR CLI and Python API"
readme = "README.md"
requires-python = ">=3.13"
@@ -72,4 +72,4 @@ select = [
]
[tool.uv]
-exclude-newer = "2025-07-14T16:26:00Z"
+exclude-newer = "2025-07-14T18:15:00Z"
diff --git a/src/atrclient/client.py b/src/atrclient/client.py
index ff83aeb..d849695 100755
--- a/src/atrclient/client.py
+++ b/src/atrclient/client.py
@@ -292,9 +292,9 @@ def app_dev_user() -> None:
def app_draft_delete(project: str, version: str, /) -> None:
jwt_value = config_jwt_usable()
host, verify_ssl = config_host_get()
- payload: dict[str, str] = {"project_name": project, "version": version}
+ args = models.api.ProjectVersion(project=project, version=version)
url = f"https://{host}/api/draft/delete"
- result = asyncio.run(web_post(url, payload, jwt_value, verify_ssl))
+ result = asyncio.run(web_post(url, args, jwt_value, verify_ssl))
print_json(result)
@@ -404,10 +404,8 @@ def app_release_start(project: str, version: str, /) ->
None:
jwt_value = config_jwt_usable()
host, verify_ssl = config_host_get()
url = f"https://{host}/api/releases/create"
-
- payload: dict[str, str] = {"project_name": project, "version": version}
-
- result = asyncio.run(web_post(url, payload, jwt_value, verify_ssl))
+ args = models.api.ProjectVersion(project=project, version=version)
+ result = asyncio.run(web_post(url, args, jwt_value, verify_ssl))
print_json(result)
@@ -461,14 +459,14 @@ def app_upload(project: str, version: str, path: str,
filepath: str, /) -> None:
with open(filepath, "rb") as f:
content = f.read()
- payload: dict[str, str] = {
- "project_name": project,
- "version": version,
- "rel_path": path,
- "content": base64.b64encode(content).decode("utf-8"),
- }
+ args = models.api.ProjectVersionRelpathContent(
+ project=project,
+ version=version,
+ relpath=path,
+ content=base64.b64encode(content).decode("utf-8"),
+ )
- result = asyncio.run(web_post(url, payload, jwt_value, verify_ssl))
+ result = asyncio.run(web_post(url, args, jwt_value, verify_ssl))
print_json(result)
@@ -490,16 +488,16 @@ def app_vote_start(
if body:
with open(body, encoding="utf-8") as f:
body_text = f.read()
- payload: dict[str, Any] = {
- "project_name": project,
- "version": version,
- "revision": revision,
- "email_to": mailing_list,
- "vote_duration": duration,
- "subject": subject or f"[VOTE] Release {project} {version}",
- "body": body_text or f"Release {project} {version} is ready for
voting.",
- }
- result = asyncio.run(web_post(url, payload, jwt_value, verify_ssl))
+ args = models.api.VoteStart(
+ project=project,
+ version=version,
+ revision=revision,
+ email_to=mailing_list,
+ vote_duration=duration,
+ subject=subject or f"[VOTE] Release {project} {version}",
+ body=body_text or f"Release {project} {version} is ready for voting.",
+ )
+ result = asyncio.run(web_post(url, args, jwt_value, verify_ssl))
print_json(result)
@@ -988,11 +986,11 @@ async def web_get_public(url: str, verify_ssl: bool =
True) -> JSON:
return data
-async def web_post(url: str, payload: dict[str, Any], jwt_token: str,
verify_ssl: bool = True) -> JSON:
+async def web_post(url: str, args: models.schema.Strict, jwt_token: str,
verify_ssl: bool = True) -> JSON:
connector = None if verify_ssl else aiohttp.TCPConnector(ssl=False)
headers = {"Authorization": f"Bearer {jwt_token}"}
async with aiohttp.ClientSession(connector=connector, headers=headers) as
session:
- async with session.post(url, json=payload) as resp:
+ async with session.post(url, json=args.model_dump()) as resp:
if resp.status not in (200, 201):
text = await resp.text()
show_error_and_exit(f"Error message from the
API:\n{resp.status} {url}\n{text}")
diff --git a/src/atrclient/models/api.py b/src/atrclient/models/api.py
index f88f552..bb668ac 100644
--- a/src/atrclient/models/api.py
+++ b/src/atrclient/models/api.py
@@ -38,34 +38,29 @@ class Task(Pagination):
status: str | None = None
-class DraftDeleteRequest(schema.Strict):
- project_name: str
- version: str
+class AsfuidPat(schema.Strict):
+ asfuid: str
+ pat: str
-class FileUploadRequest(schema.Strict):
- project_name: str
+class ProjectVersion(schema.Strict):
+ project: str
version: str
- rel_path: str
- content: str
-class PATJWTRequest(schema.Strict):
- asfuid: str
- pat: str
-
-
-class ReleaseCreateRequest(schema.Strict):
- project_name: str
+class ProjectVersionRelpathContent(schema.Strict):
+ project: str
version: str
+ relpath: str
+ content: str
class ResultCount(schema.Strict):
count: int
-class VoteStartRequest(schema.Strict):
- project_name: str
+class VoteStart(schema.Strict):
+ project: str
version: str
revision: str
email_to: str
diff --git a/src/atrclient/models/results.py b/src/atrclient/models/results.py
index 735b4e6..5f6c6f6 100644
--- a/src/atrclient/models/results.py
+++ b/src/atrclient/models/results.py
@@ -21,8 +21,6 @@ from pydantic import TypeAdapter
from . import schema
-# TODO: If we put this in atr.tasks.results, we get a circular import error
-
class HashingCheck(schema.Strict):
"""Result of the task to check the hash of a file."""
diff --git a/src/atrclient/models/sql.py b/src/atrclient/models/sql.py
index e7caab7..dea5604 100644
--- a/src/atrclient/models/sql.py
+++ b/src/atrclient/models/sql.py
@@ -834,14 +834,15 @@ def validate_instrumented_attribute(obj: Any) ->
orm.InstrumentedAttribute:
return obj
-RELEASE_LATEST_REVISION_NUMBER: Final = orm.column_property(
+RELEASE_LATEST_REVISION_NUMBER: Final = (
sqlalchemy.select(validate_instrumented_attribute(Revision.number))
.where(validate_instrumented_attribute(Revision.release_name) ==
Release.name)
.order_by(validate_instrumented_attribute(Revision.seq).desc())
.limit(1)
.correlate_except(Revision)
- .scalar_subquery(),
+ .scalar_subquery()
)
+
# https://github.com/fastapi/sqlmodel/issues/240#issuecomment-2074161775
-Release._latest_revision_number = RELEASE_LATEST_REVISION_NUMBER
+Release._latest_revision_number =
orm.column_property(RELEASE_LATEST_REVISION_NUMBER)
diff --git a/uv.lock b/uv.lock
index 74ad27b..30c2a88 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,7 +2,7 @@ version = 1
requires-python = ">=3.13"
[options]
-exclude-newer = "2025-07-14T16:26:00Z"
+exclude-newer = "2025-07-14T18:15:00Z"
[[package]]
name = "aiohappyeyeballs"
@@ -83,7 +83,7 @@ wheels = [
[[package]]
name = "apache-trusted-releases"
-version = "0.20250714.1626"
+version = "0.20250714.1815"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]