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 6f0afa8 Use a common prefix for all subcommand apps
6f0afa8 is described below
commit 6f0afa849d4d3dd24456cf3205142de6aed77625
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Jul 10 19:06:45 2025 +0100
Use a common prefix for all subcommand apps
---
pyproject.toml | 4 +--
src/atrclient/client.py | 84 ++++++++++++++++++++++++++-----------------------
tests/cli_version.t | 2 +-
uv.lock | 4 +--
4 files changed, 49 insertions(+), 45 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 5728a35..597ead7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ build-backend = "hatchling.build"
[project]
name = "apache-trusted-releases"
-version = "0.20250710.1756"
+version = "0.20250710.1806"
description = "ATR CLI and Python API"
readme = "README.md"
requires-python = ">=3.13"
@@ -48,4 +48,4 @@ atr = "atrclient.client:main"
packages = ["src/atrclient"]
[tool.uv]
-exclude-newer = "2025-07-10T17:56:00Z"
+exclude-newer = "2025-07-10T18:06:00Z"
diff --git a/src/atrclient/client.py b/src/atrclient/client.py
index 182acf7..9f13868 100755
--- a/src/atrclient/client.py
+++ b/src/atrclient/client.py
@@ -46,14 +46,14 @@ if TYPE_CHECKING:
from collections.abc import Generator
APP: cyclopts.App = cyclopts.App()
-CHECKS: cyclopts.App = cyclopts.App(name="checks", help="Check result
operations.")
-CONFIG: cyclopts.App = cyclopts.App(name="config", help="Configuration
operations.")
-DEV: cyclopts.App = cyclopts.App(name="dev", help="Developer operations.")
-DRAFT: cyclopts.App = cyclopts.App(name="draft", help="Draft operations.")
-JWT: cyclopts.App = cyclopts.App(name="jwt", help="JWT operations.")
-RELEASE: cyclopts.App = cyclopts.App(name="release", help="Release
operations.")
+APP_CHECKS: cyclopts.App = cyclopts.App(name="checks", help="Check result
operations.")
+APP_CONFIG: cyclopts.App = cyclopts.App(name="config", help="Configuration
operations.")
+APP_DEV: cyclopts.App = cyclopts.App(name="dev", help="Developer operations.")
+APP_DRAFT: cyclopts.App = cyclopts.App(name="draft", help="Draft operations.")
+APP_JWT: cyclopts.App = cyclopts.App(name="jwt", help="JWT operations.")
+APP_RELEASE: cyclopts.App = cyclopts.App(name="release", help="Release
operations.")
+APP_VOTE: cyclopts.App = cyclopts.App(name="vote", help="Vote operations.")
VERSION: str = metadata.version("apache-trusted-releases")
-VOTE: cyclopts.App = cyclopts.App(name="vote", help="Vote operations.")
YAML_DEFAULTS: dict[str, Any] = {"asf": {}, "atr": {}, "tokens": {}}
YAML_SCHEMA: strictyaml.Map = strictyaml.Map(
{
@@ -73,7 +73,9 @@ YAML_SCHEMA: strictyaml.Map = strictyaml.Map(
)
[email protected](name="exceptions", help="Get check exceptions for a release
revision.")
+@APP_CHECKS.command(
+ name="exceptions", help="Get check exceptions for a release revision."
+)
def app_checks_exceptions(
project: str,
version: str,
@@ -88,7 +90,7 @@ def app_checks_exceptions(
checks_display_status("exception", results, members=members)
[email protected](name="failures", help="Get check failures for a release
revision.")
+@APP_CHECKS.command(name="failures", help="Get check failures for a release
revision.")
def app_checks_failures(
project: str,
version: str,
@@ -103,7 +105,7 @@ def app_checks_failures(
checks_display_status("failure", results, members=members)
[email protected](name="status", help="Get check status for a release revision.")
+@APP_CHECKS.command(name="status", help="Get check status for a release
revision.")
def app_checks_status(
project: str,
version: str,
@@ -138,7 +140,7 @@ def app_checks_status(
checks_display(results, verbose)
[email protected](name="warnings", help="Get check warnings for a release
revision.")
+@APP_CHECKS.command(name="warnings", help="Get check warnings for a release
revision.")
def app_checks_warnings(
project: str,
version: str,
@@ -153,7 +155,7 @@ def app_checks_warnings(
checks_display_status("warning", results, members=members)
[email protected](name="file", help="Display the configuration file contents.")
+@APP_CONFIG.command(name="file", help="Display the configuration file
contents.")
def app_config_file() -> None:
path = config_path()
if not path.exists():
@@ -164,12 +166,12 @@ def app_config_file() -> None:
print(chunk, end="")
[email protected](name="path", help="Show the configuration file path.")
+@APP_CONFIG.command(name="path", help="Show the configuration file path.")
def app_config_path() -> None:
print(config_path())
[email protected](name="env", help="Show the environment variables.")
+@APP_DEV.command(name="env", help="Show the environment variables.")
def app_dev_env() -> None:
total = 0
for key, value in sorted(os.environ.items()):
@@ -180,7 +182,9 @@ def app_dev_env() -> None:
print(f"There are {total} ATR_* environment variables.")
[email protected](name="stamp", help="Update version and exclude-newer in
pyproject.toml.")
+@APP_DEV.command(
+ name="stamp", help="Update version and exclude-newer in pyproject.toml."
+)
def app_dev_stamp() -> None:
path = pathlib.Path("pyproject.toml")
if not path.exists():
@@ -217,6 +221,16 @@ def app_dev_stamp() -> None:
print("Updated tests/cli_version.t.")
+@APP_DRAFT.command(name="delete", help="Delete a draft release.")
+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}
+ url = f"https://{host}/api/draft/delete"
+ result = asyncio.run(web_post(url, payload, jwt_value, verify_ssl))
+ print(result)
+
+
@APP.command(name="docs", help="Show comprehensive CLI documentation in
Markdown.")
def app_docs() -> None:
old_help_format = APP.help_format
@@ -240,7 +254,7 @@ def app_drop(path: str, /) -> None:
print(f"Removed {path}.")
[email protected](name="dump", help="Show decoded JWT payload from stored config.")
+@APP_JWT.command(name="dump", help="Show decoded JWT payload from stored
config.")
def app_jwt_dump() -> None:
jwt_value = config_jwt_get()
@@ -256,7 +270,7 @@ def app_jwt_dump() -> None:
print(json.dumps(payload, indent=None))
[email protected](name="info", help="Show JWT payload in human-readable form.")
+@APP_JWT.command(name="info", help="Show JWT payload in human-readable form.")
def app_jwt_info() -> None:
_jwt_value, payload = config_jwt_payload()
@@ -269,7 +283,7 @@ def app_jwt_info() -> None:
print("\n".join(lines))
[email protected](
+@APP_JWT.command(
name="refresh", help="Fetch a JWT using the stored PAT and store it in
config."
)
def app_jwt_refresh(asf_uid: str | None = None) -> None:
@@ -277,7 +291,7 @@ def app_jwt_refresh(asf_uid: str | None = None) -> None:
print(jwt_value)
[email protected](name="show", help="Show stored JWT token.")
+@APP_JWT.command(name="show", help="Show stored JWT token.")
def app_jwt_show() -> None:
return app_show("tokens.jwt")
@@ -293,7 +307,7 @@ def app_list(project: str, version: str, revision: str |
None = None, /) -> None
print(result)
[email protected](name="info", help="Show information about a release.")
+@APP_RELEASE.command(name="info", help="Show information about a release.")
def app_release_info(project: str, version: str, /) -> None:
host, verify_ssl = config_host_get()
url = f"https://{host}/api/releases/{project}/{version}"
@@ -301,7 +315,7 @@ def app_release_info(project: str, version: str, /) -> None:
print(result)
[email protected](name="list", help="List releases for a project.")
+@APP_RELEASE.command(name="list", help="List releases for a project.")
def app_release_list(project: str, /) -> None:
# TODO: Support showing all of a user's releases if no project is provided
host, verify_ssl = config_host_get()
@@ -310,7 +324,7 @@ def app_release_list(project: str, /) -> None:
releases_display(result)
[email protected](name="start", help="Start a release.")
+@APP_RELEASE.command(name="start", help="Start a release.")
def app_release_start(project: str, version: str, /) -> None:
jwt_value = config_jwt_usable()
host, verify_ssl = config_host_get()
@@ -378,7 +392,7 @@ def app_upload(project: str, version: str, path: str,
filepath: str, /) -> None:
print(result)
[email protected](name="start", help="Start a vote.")
+@APP_VOTE.command(name="start", help="Start a vote.")
def app_vote_start(
project: str,
version: str,
@@ -411,16 +425,6 @@ def app_vote_start(
print(result)
[email protected](name="delete", help="Delete a draft release.")
-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}
- url = f"https://{host}/api/draft/delete"
- result = asyncio.run(web_post(url, payload, jwt_value, verify_ssl))
- print(result)
-
-
def checks_display(results: list[dict[str, Any]], verbose: bool = False) ->
None:
if not results:
print("No check results found for this revision.")
@@ -768,13 +772,13 @@ def show_warning(message: str) -> None:
def subcommands_register(app: cyclopts.App) -> None:
- app.command(CHECKS)
- app.command(CONFIG)
- app.command(DEV)
- app.command(DRAFT)
- app.command(JWT)
- app.command(RELEASE)
- app.command(VOTE)
+ app.command(APP_CHECKS)
+ app.command(APP_CONFIG)
+ app.command(APP_DEV)
+ app.command(APP_DRAFT)
+ app.command(APP_JWT)
+ app.command(APP_RELEASE)
+ app.command(APP_VOTE)
def timestamp_format(ts: int | str | None) -> str | None:
diff --git a/tests/cli_version.t b/tests/cli_version.t
index efde72d..de10014 100644
--- a/tests/cli_version.t
+++ b/tests/cli_version.t
@@ -1,2 +1,2 @@
$ atr --version
-0.20250710.1756
+0.20250710.1806
diff --git a/uv.lock b/uv.lock
index 8f76a75..20dd570 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,7 +2,7 @@ version = 1
requires-python = ">=3.13"
[options]
-exclude-newer = "2025-07-10T17:56:00Z"
+exclude-newer = "2025-07-10T18:06:00Z"
[[package]]
name = "aiohappyeyeballs"
@@ -74,7 +74,7 @@ wheels = [
[[package]]
name = "apache-trusted-releases"
-version = "0.20250710.1756"
+version = "0.20250710.1806"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]