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 e3e279d  Fix a problem with the api command
e3e279d is described below

commit e3e279d926d86c1591fa4c0137aeace1b2c42658
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Jul 28 20:20:35 2025 +0100

    Fix a problem with the api command
---
 pyproject.toml              |  4 +--
 src/atrclient/client.py     |  6 ++--
 src/atrclient/models/api.py | 18 +++++------
 src/atrclient/models/sql.py | 73 +++++++++++++++++++++++++++------------------
 uv.lock                     |  4 +--
 5 files changed, 60 insertions(+), 45 deletions(-)

diff --git a/pyproject.toml b/pyproject.toml
index 844a6c1..fbf9c23 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ build-backend = "hatchling.build"
 
 [project]
 name            = "apache-trusted-releases"
-version         = "0.20250728.1817"
+version         = "0.20250728.1919"
 description     = "ATR CLI and Python API"
 readme          = "README.md"
 requires-python = ">=3.13"
@@ -74,4 +74,4 @@ select = [
 ]
 
 [tool.uv]
-exclude-newer = "2025-07-28T18:17:00Z"
+exclude-newer = "2025-07-28T19:19:00Z"
diff --git a/src/atrclient/client.py b/src/atrclient/client.py
index 3a9c860..90f505f 100755
--- a/src/atrclient/client.py
+++ b/src/atrclient/client.py
@@ -321,7 +321,7 @@ def app_announce(
 
 
 @APP.command(name="api", help="Call the API directly.")
-async def app_api(path: str, /, **kwargs: str) -> None:
+def app_api(path: str, /, **kwargs: str) -> None:
     jwt_value = config_jwt_usable()
     host, verify_ssl = config_host_get()
     url = f"https://{host}/api{path}";
@@ -329,14 +329,14 @@ async def app_api(path: str, /, **kwargs: str) -> None:
     #     print(url)
     #     print(kwargs)
     if "_version" in kwargs:
-        # There's a bug in Cyclopts where it does not pass --version to 
**kwargs
+        # TODO: There's a bug in Cyclopts where it does not pass --version to 
**kwargs
         kwargs["version"] = kwargs["_version"]
         del kwargs["_version"]
     if not is_json(kwargs):
         show_error_and_exit(f"Unexpected API response: {kwargs}")
     if not is_json_dict(kwargs):
         show_error_and_exit(f"Unexpected API response: {kwargs}")
-    json_data = await web_post_json(url, kwargs, jwt_value, verify_ssl)
+    json_data = asyncio.run(web_post_json(url, kwargs, jwt_value, verify_ssl))
     print(json.dumps(json_data, indent=None))
 
 
diff --git a/src/atrclient/models/api.py b/src/atrclient/models/api.py
index 3a565d8..820d466 100644
--- a/src/atrclient/models/api.py
+++ b/src/atrclient/models/api.py
@@ -69,8 +69,8 @@ class ChecksOngoingResults(schema.Strict):
     ongoing: int
 
 
-class CommitteesResults(schema.Strict):
-    endpoint: Literal["/committees"] = schema.Field(alias="endpoint")
+class CommitteesGetResults(schema.Strict):
+    endpoint: Literal["/committees/get"] = schema.Field(alias="endpoint")
     committee: sql.Committee
 
 
@@ -139,9 +139,9 @@ class KeysAddResults(schema.Strict):
     fingerprint: str
 
 
-class KeysCommitteeResults(schema.Strict):
-    endpoint: Literal["/keys/committee"] = schema.Field(alias="endpoint")
-    keys: Sequence[sql.PublicSigningKey]
+# class KeysCommitteeResults(schema.Strict):
+#     endpoint: Literal["/keys/committee"] = schema.Field(alias="endpoint")
+#     keys: Sequence[sql.PublicSigningKey]
 
 
 class KeysDeleteArgs(schema.Strict):
@@ -416,7 +416,7 @@ Results = Annotated[
     AnnounceResults
     | ChecksListResults
     | ChecksOngoingResults
-    | CommitteesResults
+    | CommitteesGetResults
     | CommitteesKeysResults
     | CommitteesListResults
     | CommitteesProjectsResults
@@ -426,7 +426,7 @@ Results = Annotated[
     | KeysAddResults
     | KeysDeleteResults
     | KeysGetResults
-    | KeysCommitteeResults
+    # | KeysCommitteeResults
     | KeysUploadResults
     | KeysUserResults
     | ListResults
@@ -469,7 +469,7 @@ def validator[T](t: type[T]) -> Callable[[Any], T]:
 validate_announce = validator(AnnounceResults)
 validate_checks_list = validator(ChecksListResults)
 validate_checks_ongoing = validator(ChecksOngoingResults)
-validate_committees = validator(CommitteesResults)
+validate_committees_get = validator(CommitteesGetResults)
 validate_committees_keys = validator(CommitteesKeysResults)
 validate_committees_list = validator(CommitteesListResults)
 validate_committees_projects = validator(CommitteesProjectsResults)
@@ -477,7 +477,7 @@ validate_draft_delete = validator(DraftDeleteResults)
 validate_jwt = validator(JwtResults)
 validate_keys = validator(KeysResults)
 validate_keys_add = validator(KeysAddResults)
-validate_keys_committee = validator(KeysCommitteeResults)
+# validate_keys_committee = validator(KeysCommitteeResults)
 validate_keys_delete = validator(KeysDeleteResults)
 validate_keys_get = validator(KeysGetResults)
 validate_keys_upload = validator(KeysUploadResults)
diff --git a/src/atrclient/models/sql.py b/src/atrclient/models/sql.py
index b224a5e..9af0a0a 100644
--- a/src/atrclient/models/sql.py
+++ b/src/atrclient/models/sql.py
@@ -192,6 +192,11 @@ class ResultsJSON(sqlalchemy.types.TypeDecorator):
 
 # SQL models
 
+
+def example(value: Any) -> dict[Literal["schema_extra"], dict[str, Any]]:
+    return {"schema_extra": {"json_schema_extra": {"examples": [value]}}}
+
+
 # SQL models with no dependencies
 
 
@@ -309,8 +314,8 @@ class TextValue(sqlmodel.SQLModel, table=True):
 class Committee(sqlmodel.SQLModel, table=True):
     # TODO: Consider using key or label for primary string keys
     # Then we can use simply "name" for full_name, and make it str rather than 
str | None
-    name: str = sqlmodel.Field(unique=True, primary_key=True)
-    full_name: str | None = sqlmodel.Field(default=None)
+    name: str = sqlmodel.Field(unique=True, primary_key=True, 
**example("example"))
+    full_name: str | None = sqlmodel.Field(default=None, **example("Example"))
     # True only if this is an incubator podling with a PPMC
     is_podling: bool = sqlmodel.Field(default=False)
 
@@ -331,9 +336,15 @@ class Committee(sqlmodel.SQLModel, table=True):
     # M-1: Project -> Committee
     projects: list["Project"] = 
sqlmodel.Relationship(back_populates="committee")
 
-    committee_members: list[str] = sqlmodel.Field(default_factory=list, 
sa_column=sqlalchemy.Column(sqlalchemy.JSON))
-    committers: list[str] = sqlmodel.Field(default_factory=list, 
sa_column=sqlalchemy.Column(sqlalchemy.JSON))
-    release_managers: list[str] = sqlmodel.Field(default_factory=list, 
sa_column=sqlalchemy.Column(sqlalchemy.JSON))
+    committee_members: list[str] = sqlmodel.Field(
+        default_factory=list, sa_column=sqlalchemy.Column(sqlalchemy.JSON), 
**example(["sbp", "tn", "wave"])
+    )
+    committers: list[str] = sqlmodel.Field(
+        default_factory=list, sa_column=sqlalchemy.Column(sqlalchemy.JSON), 
**example(["sbp", "tn", "wave"])
+    )
+    release_managers: list[str] = sqlmodel.Field(
+        default_factory=list, sa_column=sqlalchemy.Column(sqlalchemy.JSON), 
**example(["wave"])
+    )
 
     # M-M: Committee -> [PublicSigningKey]
     # M-M: PublicSigningKey -> [Committee]
@@ -356,12 +367,12 @@ def see_also(arg: Any) -> None:
 class Project(sqlmodel.SQLModel, table=True):
     # TODO: Consider using key or label for primary string keys
     # Then we can use simply "name" for full_name, and make it str rather than 
str | None
-    name: str = sqlmodel.Field(unique=True, primary_key=True)
+    name: str = sqlmodel.Field(unique=True, primary_key=True, 
**example("example"))
     # TODO: Ideally full_name would be unique for str only, but that's complex
     # We always include "Apache" in the full_name
-    full_name: str | None = sqlmodel.Field(default=None)
+    full_name: str | None = sqlmodel.Field(default=None, **example("Apache 
Example"))
 
-    status: ProjectStatus = sqlmodel.Field(default=ProjectStatus.ACTIVE)
+    status: ProjectStatus = sqlmodel.Field(default=ProjectStatus.ACTIVE, 
**example(ProjectStatus.ACTIVE))
 
     # M-1: Project -> Project
     # 1-M: (Project.child_project is missing, would be Project -> [Project])
@@ -369,13 +380,13 @@ class Project(sqlmodel.SQLModel, table=True):
     # NOTE: Neither "Project" | None nor "Project | None" works
     super_project: Optional["Project"] = sqlmodel.Relationship()
 
-    description: str | None = sqlmodel.Field(default=None)
-    category: str | None = sqlmodel.Field(default=None)
-    programming_languages: str | None = sqlmodel.Field(default=None)
+    description: str | None = sqlmodel.Field(default=None, **example("Example 
is a simple example project"))
+    category: str | None = sqlmodel.Field(default=None, 
**example("data,storage"))
+    programming_languages: str | None = sqlmodel.Field(default=None, 
**example("c,python"))
 
     # M-1: Project -> Committee
     # 1-M: Committee -> [Project]
-    committee_name: str | None = sqlmodel.Field(default=None, 
foreign_key="committee.name")
+    committee_name: str | None = sqlmodel.Field(default=None, 
foreign_key="committee.name", **example("example"))
     committee: Committee | None = 
sqlmodel.Relationship(back_populates="projects")
     see_also(Committee.projects)
 
@@ -396,9 +407,11 @@ class Project(sqlmodel.SQLModel, table=True):
     )
 
     created: datetime.datetime = sqlmodel.Field(
-        default_factory=lambda: datetime.datetime.now(datetime.UTC), 
sa_column=sqlalchemy.Column(UTCDateTime)
+        default_factory=lambda: datetime.datetime.now(datetime.UTC),
+        sa_column=sqlalchemy.Column(UTCDateTime),
+        **example(datetime.datetime(2025, 5, 1, 1, 2, 3, tzinfo=datetime.UTC)),
     )
-    created_by: str | None = sqlmodel.Field(default=None)
+    created_by: str | None = sqlmodel.Field(default=None, **example("user"))
 
     @property
     def display_name(self) -> str:
@@ -646,10 +659,6 @@ class Release(sqlmodel.SQLModel, table=True):
 # SQL models referencing Committee, Project, or Release
 
 
-def example(value: Any) -> dict[Literal["schema_extra"], dict[str, Any]]:
-    return {"schema_extra": {"json_schema_extra": {"examples": [value]}}}
-
-
 # CheckResult: Release
 class CheckResult(sqlmodel.SQLModel, table=True):
     # TODO: We have default=None here with a field typed int, not int | None
@@ -657,19 +666,19 @@ class CheckResult(sqlmodel.SQLModel, table=True):
 
     # M-1: CheckResult -> Release
     # 1-M: Release -C-> [CheckResult]
-    release_name: str = sqlmodel.Field(foreign_key="release.name", 
ondelete="CASCADE")
+    release_name: str = sqlmodel.Field(foreign_key="release.name", 
ondelete="CASCADE", **example("example-0.0.1"))
     release: Release = sqlmodel.Relationship(back_populates="check_results")
 
     # We don't call this latest_revision_number, because it might not be the 
latest
     revision_number: str | None = sqlmodel.Field(default=None, index=True, 
**example("00005"))
-    checker: str = 
sqlmodel.Field(**example("atr.tasks.checks.hashing.HashingCheck"))
+    checker: str = sqlmodel.Field(**example("atr.tasks.checks.license.files"))
     primary_rel_path: str | None = sqlmodel.Field(
         default=None, index=True, 
**example("apache-example-0.0.1-source.tar.gz")
     )
     member_rel_path: str | None = sqlmodel.Field(default=None, index=True, 
**example("apache-example-0.0.1/pom.xml"))
     created: datetime.datetime = sqlmodel.Field(
         sa_column=sqlalchemy.Column(UTCDateTime),
-        **example(datetime.datetime(2025, 1, 1, 12, 0, 0, 
tzinfo=datetime.UTC)),
+        **example(datetime.datetime(2025, 5, 1, 1, 2, 3, tzinfo=datetime.UTC)),
     )
     status: CheckResultStatus = 
sqlmodel.Field(default=CheckResultStatus.SUCCESS, 
**example(CheckResultStatus.SUCCESS))
     message: str = sqlmodel.Field(**example("sha512 matches for 
apache-example-0.0.1/pom.xml"))
@@ -698,13 +707,17 @@ class DistributionChannel(sqlmodel.SQLModel, table=True):
 # PublicSigningKey: Committee
 class PublicSigningKey(sqlmodel.SQLModel, table=True):
     # The fingerprint must be stored as lowercase hex
-    fingerprint: str = sqlmodel.Field(primary_key=True, unique=True)
+    fingerprint: str = sqlmodel.Field(
+        primary_key=True, unique=True, 
**example("0123456789abcdef0123456789abcdef01234567")
+    )
     # The algorithm is an RFC 4880 algorithm ID
-    algorithm: int
+    algorithm: int = sqlmodel.Field(**example(1))
     # Key length in bits
-    length: int
+    length: int = sqlmodel.Field(**example(4096))
     # Creation date
-    created: datetime.datetime = 
sqlmodel.Field(sa_column=sqlalchemy.Column(UTCDateTime))
+    created: datetime.datetime = sqlmodel.Field(
+        sa_column=sqlalchemy.Column(UTCDateTime), 
**example(datetime.datetime(2025, 5, 1, 1, 2, 3, tzinfo=datetime.UTC))
+    )
     # Latest self signature
     latest_self_signature: datetime.datetime | None = sqlmodel.Field(
         default=None, sa_column=sqlalchemy.Column(UTCDateTime)
@@ -712,15 +725,17 @@ class PublicSigningKey(sqlmodel.SQLModel, table=True):
     # Expiration date
     expires: datetime.datetime | None = sqlmodel.Field(default=None, 
sa_column=sqlalchemy.Column(UTCDateTime))
     # The primary UID declared in the key
-    primary_declared_uid: str | None
+    primary_declared_uid: str | None = sqlmodel.Field(**example("User 
<[email protected]>"))
     # The secondary UIDs declared in the key
     secondary_declared_uids: list[str] = sqlmodel.Field(
-        default_factory=list, sa_column=sqlalchemy.Column(sqlalchemy.JSON)
+        default_factory=list, sa_column=sqlalchemy.Column(sqlalchemy.JSON), 
**example(["User <[email protected]>"])
     )
     # The UID used by Apache, if available
-    apache_uid: str | None
+    apache_uid: str | None = sqlmodel.Field(**example("user"))
     # The ASCII armored key
-    ascii_armored_key: str
+    ascii_armored_key: str = sqlmodel.Field(
+        **example("-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n...\n-----END PGP 
PUBLIC KEY BLOCK-----\n")
+    )
 
     # M-M: PublicSigningKey -> [Committee]
     # M-M: Committee -> [PublicSigningKey]
diff --git a/uv.lock b/uv.lock
index 2bf35e5..4c1305a 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,7 +2,7 @@ version = 1
 requires-python = ">=3.13"
 
 [options]
-exclude-newer = "2025-07-28T18:17:00Z"
+exclude-newer = "2025-07-28T19:19:00Z"
 
 [[package]]
 name = "aiohappyeyeballs"
@@ -83,7 +83,7 @@ wheels = [
 
 [[package]]
 name = "apache-trusted-releases"
-version = "0.20250728.1817"
+version = "0.20250728.1919"
 source = { editable = "." }
 dependencies = [
     { name = "aiohttp" },


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

Reply via email to