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 60e2ea7 Add commands to delete and list ignores, and rename some
commands
60e2ea7 is described below
commit 60e2ea7e3bf5a8a479689a3a138d6b6e08644cc0
Author: Sean B. Palmer <[email protected]>
AuthorDate: Wed Jul 30 15:48:56 2025 +0100
Add commands to delete and list ignores, and rename some commands
---
COMMANDS.md | 174 ++++++++++++++++++++++++++++++++-----------
docs/release-workflow.md | 6 +-
pyproject.toml | 4 +-
src/atrclient/client.py | 176 +++++++++++++++++++++++++-------------------
src/atrclient/models/api.py | 61 +++++++++------
src/atrclient/models/sql.py | 4 +
tests/cli_keys.t | 10 +--
tests/cli_workflow.t | 6 +-
tests/test_all.py | 4 +-
uv.lock | 4 +-
10 files changed, 294 insertions(+), 155 deletions(-)
diff --git a/COMMANDS.md b/COMMANDS.md
index 127a646..d11bf0a 100644
--- a/COMMANDS.md
+++ b/COMMANDS.md
@@ -27,10 +27,25 @@ Announce a release.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
-## atr checks
+## atr api
```
-Usage: checks COMMAND
+Usage: api [ARGS] [OPTIONS]
+
+Call the API directly.
+
+╭─ Arguments
──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ * PATH [required]
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Parameters
─────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ --[KEYWORD]
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+```
+
+## atr check
+
+```
+Usage: check COMMAND
Check result operations.
@@ -43,7 +58,7 @@ Check result operations.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
-### atr checks exceptions
+### atr check exceptions
```
Usage: exceptions [ARGS] [OPTIONS]
@@ -60,7 +75,7 @@ Get check exceptions for a release revision.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
-### atr checks failures
+### atr check failures
```
Usage: failures [ARGS] [OPTIONS]
@@ -77,7 +92,7 @@ Get check failures for a release revision.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
-### atr checks status
+### atr check status
```
Usage: status [ARGS] [OPTIONS]
@@ -94,7 +109,7 @@ Get check status for a release revision.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
-### atr checks wait
+### atr check wait
```
Usage: wait [ARGS] [OPTIONS]
@@ -112,7 +127,7 @@ Wait for checks to be completed.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
-### atr checks warnings
+### atr check warnings
```
Usage: warnings [ARGS] [OPTIONS]
@@ -168,7 +183,9 @@ Developer operations.
╭─ Commands
───────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ delete Delete a release.
│
│ env Show the environment variables.
│
+│ key Return a test OpenPGP key.
│
│ pat Read a PAT from development configuration.
│
+│ pwd Show the current working directory.
│
│ stamp Update version and exclude-newer in pyproject.toml.
│
│ token Generate a random alphabetical token.
│
│ user Show the value of $USER.
│
@@ -196,6 +213,14 @@ Usage: env
Show the environment variables.
```
+### atr dev key
+
+```
+Usage: key
+
+Return a test OpenPGP key.
+```
+
### atr dev pat
```
@@ -204,6 +229,14 @@ Usage: pat
Read a PAT from development configuration.
```
+### atr dev pwd
+
+```
+Usage: pwd
+
+Show the current working directory.
+```
+
### atr dev stamp
```
@@ -260,6 +293,53 @@ Remove a configuration key using dot notation.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
+## atr ignore
+
+```
+Usage: ignore COMMAND
+
+Ignore operations.
+
+╭─ Commands
───────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ add Add a check ignore.
│
+│ delete Delete a check ignore.
│
+│ list List check ignores.
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+```
+
+### atr ignore add
+
+```
+Usage: add [ARGS] [OPTIONS]
+
+Add a check ignore.
+
+╭─ Arguments
──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ * COMMITTEE [required]
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Parameters
─────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ RELEASE --release
│
+│ REVISION --revision
│
+│ CHECKER --checker
│
+│ PRIMARY-REL-PATH --primary-rel-path
│
+│ MEMBER-REL-PATH --member-rel-path
│
+│ STATUS --status [choices: exception, failure, warning]
│
+│ MESSAGE --message
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+```
+
+### atr ignore list
+
+```
+Usage: list [ARGS]
+
+List check ignores.
+
+╭─ Arguments
──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ * COMMITTEE [required]
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+```
+
## atr jwt
```
@@ -311,28 +391,6 @@ Usage: show
Show stored JWT token.
```
-## atr keys
-
-```
-Usage: keys
-
-Keys operations.
-```
-
-## atr list
-
-```
-Usage: list [ARGS]
-
-List all files within a release.
-
-╭─ Arguments
──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│ * PROJECT [required]
│
-│ * VERSION [required]
│
-│ REVISION
│
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-```
-
## atr release
```
@@ -373,6 +431,21 @@ List all revisions for a release.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
+## atr rsync
+
+```
+Usage: rsync [ARGS]
+
+Rsync a release.
+
+╭─ Arguments
──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ * PROJECT [required]
│
+│ * VERSION [required]
│
+│ SOURCE [default: .]
│
+│ TARGET [default: /]
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+```
+
## atr set
```
@@ -400,30 +473,33 @@ SSH operations.
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
-### atr ssh add
+## atr upload
```
-Usage: add [ARGS]
+Usage: upload [ARGS]
-Add an SSH key.
+Upload a file to a release.
╭─ Arguments
──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│ * TEXT [required]
│
+│ * PROJECT [required]
│
+│ * VERSION [required]
│
+│ * PATH [required]
│
+│ * FILEPATH [required]
│
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
-## atr upload
+## atr verify
```
-Usage: upload [ARGS]
+Usage: verify [ARGS] [OPTIONS]
-Upload a file to a release.
+Verify an artifact.
╭─ Arguments
──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│ * PROJECT [required]
│
-│ * VERSION [required]
│
-│ * PATH [required]
│
-│ * FILEPATH [required]
│
+│ * URL [required]
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Parameters
─────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ VERBOSE --verbose --no-verbose [default: False]
│
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
@@ -435,8 +511,9 @@ Usage: vote COMMAND
Vote operations.
╭─ Commands
───────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│ resolve Resolve a vote.
│
-│ start Start a vote.
│
+│ resolve Resolve a vote.
│
+│ start Start a vote.
│
+│ tabulate Tabulate a vote.
│
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
@@ -453,3 +530,16 @@ Resolve a vote.
│ * RESOLUTION --resolution [choices: passed, failed] [required]
│
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
+
+### atr vote tabulate
+
+```
+Usage: tabulate [ARGS]
+
+Tabulate a vote.
+
+╭─ Arguments
──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ * PROJECT [required]
│
+│ * VERSION [required]
│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+```
diff --git a/docs/release-workflow.md b/docs/release-workflow.md
index b70f49c..3374b26 100644
--- a/docs/release-workflow.md
+++ b/docs/release-workflow.md
@@ -30,7 +30,7 @@ Your release is in the ① COMPOSE phase.
```
atr upload your-project 0.1+test example.txt "$FILE_TO_UPLOAD"
-atr checks wait your-project 0.1+test
+atr check wait your-project 0.1+test
atr vote start your-project 0.1+test 00002 -m "${ASF_UID}@apache.org"
```
@@ -93,10 +93,10 @@ Your release is then in the ① COMPOSE phase. You must add a
file to be able to
```
atr upload your-project 0.1+test example.txt "$FILE_TO_UPLOAD"
-atr checks wait your-project 0.1+test
+atr check wait your-project 0.1+test
```
-To see the status of the checks here, you could run `atr checks status
your-project 0.1+test 00002`. You need to know the revision to get the status,
but we plan to make this command use the most recent revision if omitted.
+To see the status of the checks here, you could run `atr check status
your-project 0.1+test 00002`. You need to know the revision to get the status,
but we plan to make this command use the most recent revision if omitted.
### Vote
diff --git a/pyproject.toml b/pyproject.toml
index 3307ef1..77969fe 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ build-backend = "hatchling.build"
[project]
name = "apache-trusted-releases"
-version = "0.20250729.1943"
+version = "0.20250730.1448"
description = "ATR CLI and Python API"
readme = "README.md"
requires-python = ">=3.13"
@@ -79,4 +79,4 @@ filterwarnings = [
]
[tool.uv]
-exclude-newer = "2025-07-29T19:43:00Z"
+exclude-newer = "2025-07-30T14:48:00Z"
diff --git a/src/atrclient/client.py b/src/atrclient/client.py
index 931aeea..e3af369 100755
--- a/src/atrclient/client.py
+++ b/src/atrclient/client.py
@@ -54,12 +54,13 @@ if TYPE_CHECKING:
from collections.abc import Callable, Generator, Sequence
APP: cyclopts.App = cyclopts.App()
-APP_CHECKS: cyclopts.App = cyclopts.App(name="checks", help="Check result
operations.")
+APP_CHECK: cyclopts.App = cyclopts.App(name="check", 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_IGNORE: cyclopts.App = cyclopts.App(name="ignore", help="Ignore
operations.")
APP_JWT: cyclopts.App = cyclopts.App(name="jwt", help="JWT operations.")
-APP_KEYS: cyclopts.App = cyclopts.App(name="keys", help="Keys operations.")
+APP_KEY: cyclopts.App = cyclopts.App(name="key", help="Key operations.")
APP_RELEASE: cyclopts.App = cyclopts.App(name="release", help="Release
operations.")
APP_SSH: cyclopts.App = cyclopts.App(name="ssh", help="SSH operations.")
APP_VOTE: cyclopts.App = cyclopts.App(name="vote", help="Vote operations.")
@@ -156,12 +157,6 @@ def api_post(path: str) -> Callable[[Callable[[ApiPost,
A], R]], Callable[[A], R
return decorator
-@api_post("/checks/ignore/add")
-def api_checks_ignore_add(api: ApiPost, args: models.api.ChecksIgnoreAddArgs)
-> models.api.ChecksIgnoreAddResults:
- response = api.post(args)
- return models.api.validate_checks_ignore_add(response)
-
-
@api_get("/checks/list")
def api_checks_list(api: ApiGet, project: str, version: str, revision: str) ->
models.api.ChecksListResults:
response = api.get(project, version, revision)
@@ -176,6 +171,24 @@ def api_checks_ongoing(
return models.api.validate_checks_ongoing(response)
+@api_post("/ignore/add")
+def api_ignore_add(api: ApiPost, args: models.api.IgnoreAddArgs) ->
models.api.IgnoreAddResults:
+ response = api.post(args)
+ return models.api.validate_ignore_add(response)
+
+
+@api_post("/ignore/delete")
+def api_ignore_delete(api: ApiPost, args: models.api.IgnoreDeleteArgs) ->
models.api.IgnoreDeleteResults:
+ response = api.post(args)
+ return models.api.validate_ignore_delete(response)
+
+
+@api_get("/ignore/list")
+def api_ignore_list(api: ApiGet, committee: str) ->
models.api.IgnoreListResults:
+ response = api.get(committee)
+ return models.api.validate_ignore_list(response)
+
+
@api_post("/key/add")
def api_key_add(api: ApiPost, args: models.api.KeyAddArgs) ->
models.api.KeyAddResults:
response = api.post(args)
@@ -354,8 +367,8 @@ def app_api(path: str, /, **kwargs: str) -> None:
print(json.dumps(json_data, indent=None))
-@APP_CHECKS.command(name="exceptions", help="Get check exceptions for a
release revision.")
-def app_checks_exceptions(
+@APP_CHECK.command(name="exceptions", help="Get check exceptions for a release
revision.")
+def app_check_exceptions(
project: str,
version: str,
revision: str,
@@ -366,8 +379,8 @@ def app_checks_exceptions(
checks_display_status("exception", checks_list.checks, members=members)
-@APP_CHECKS.command(name="failures", help="Get check failures for a release
revision.")
-def app_checks_failures(
+@APP_CHECK.command(name="failures", help="Get check failures for a release
revision.")
+def app_check_failures(
project: str,
version: str,
revision: str,
@@ -377,54 +390,9 @@ def app_checks_failures(
checks_list = api_checks_list(project, version, revision)
checks_display_status("failure", checks_list.checks, members=members)
- # committee_name: str = schema.Field(..., **example("example"))
- # release_glob: str | None = schema.Field(default=None,
**example("example-0.0.*"))
- # revision_number: str | None = schema.Field(default=None,
**example("00001"))
- # checker_glob: str | None = schema.Field(default=None,
**example("atr.tasks.checks.license.files"))
- # primary_rel_path_glob: str | None = schema.Field(default=None,
**example("apache-example-0.0.1-*.tar.gz"))
- # member_rel_path_glob: str | None = schema.Field(default=None,
**example("apache-example-0.0.1/*.xml"))
- # status: sql.CheckResultStatusIgnore | None = schema.Field(
- # default=None, **example(sql.CheckResultStatusIgnore.FAILURE)
- # )
- # message_glob: str | None = schema.Field(default=None, **example("sha512
matches for apache-example-0.0.1/*.xml"))
-
-
-@APP_CHECKS.command(name="ignore", help="Ignore a check result.")
-def app_checks_ignore(
- committee: str,
- /,
- release: str | None = None,
- revision: str | None = None,
- checker: str | None = None,
- primary_rel_path: str | None = None,
- member_rel_path: str | None = None,
- status: models.sql.CheckResultStatusIgnore | None = None,
- message: str | None = None,
-) -> None:
- args = models.api.ChecksIgnoreAddArgs(
- committee_name=committee,
- release_glob=release,
- revision_number=revision,
- checker_glob=checker,
- primary_rel_path_glob=primary_rel_path,
- member_rel_path_glob=member_rel_path,
- status=status,
- message_glob=message,
- )
- api_checks_ignore_add(args)
- print("Check result ignored for:")
- print(f" Committee: {committee}")
- print(f" Release (glob): {release}")
- print(f" Revision: {revision}")
- print(f" Checker (glob): {checker}")
- print(f" Primary rel path (glob): {primary_rel_path}")
- print(f" Member rel path (glob): {member_rel_path}")
- print(f" Status: {status}")
- print(f" Message (glob): {message}")
-
-@APP_CHECKS.command(name="status", help="Get check status for a release
revision.")
-def app_checks_status(
+@APP_CHECK.command(name="status", help="Get check status for a release
revision.")
+def app_check_status(
project: str,
version: str,
/,
@@ -450,8 +418,8 @@ def app_checks_status(
checks_display(checks_list.checks, verbose)
-@APP_CHECKS.command(name="wait", help="Wait for checks to be completed.")
-def app_checks_wait(
+@APP_CHECK.command(name="wait", help="Wait for checks to be completed.")
+def app_check_wait(
project: str,
version: str,
/,
@@ -477,8 +445,8 @@ def app_checks_wait(
print("Checks completed.")
-@APP_CHECKS.command(name="warnings", help="Get check warnings for a release
revision.")
-def app_checks_warnings(
+@APP_CHECK.command(name="warnings", help="Get check warnings for a release
revision.")
+def app_check_warnings(
project: str,
version: str,
revision: str,
@@ -691,6 +659,63 @@ def app_drop(path: str, /) -> None:
print(f"Removed {path}.")
+@APP_IGNORE.command(name="add", help="Add a check ignore.")
+def app_ignore_add(
+ committee: str,
+ /,
+ release: str | None = None,
+ revision: str | None = None,
+ checker: str | None = None,
+ primary_rel_path: str | None = None,
+ member_rel_path: str | None = None,
+ status: models.sql.CheckResultStatusIgnore | None = None,
+ message: str | None = None,
+) -> None:
+ args = models.api.IgnoreAddArgs(
+ committee_name=committee,
+ release_glob=release,
+ revision_number=revision,
+ checker_glob=checker,
+ primary_rel_path_glob=primary_rel_path,
+ member_rel_path_glob=member_rel_path,
+ status=status,
+ message_glob=message,
+ )
+ api_ignore_add(args)
+ print("Check result ignored for:")
+ print(f" Committee: {committee}")
+ print(f" Release (glob): {release}")
+ print(f" Revision: {revision}")
+ print(f" Checker (glob): {checker}")
+ print(f" Primary rel path (glob): {primary_rel_path}")
+ print(f" Member rel path (glob): {member_rel_path}")
+ print(f" Status: {status}")
+ print(f" Message (glob): {message}")
+
+
+@APP_IGNORE.command(name="delete", help="Delete a check ignore.")
+def app_ignore_delete(
+ committee: str,
+ id: int,
+ /,
+) -> None:
+ args = models.api.IgnoreDeleteArgs(committee=committee, id=id)
+ api_ignore_delete(args)
+ print("Check ignore deleted for:")
+ print(f" Committee: {committee}")
+ print(f" ID: {id}")
+
+
+@APP_IGNORE.command(name="list", help="List check ignores.")
+def app_ignore_list(
+ committee: str,
+ /,
+) -> None:
+ ignores = api_ignore_list(committee)
+ for ignore in ignores.ignores:
+ print(ignore.model_dump_json(indent=None))
+
+
@APP_JWT.command(name="dump", help="Show decoded JWT payload from stored
config.")
def app_jwt_dump() -> None:
jwt_value = config_jwt_get()
@@ -735,8 +760,8 @@ def app_jwt_show() -> None:
return app_show("tokens.jwt")
-@APP_KEYS.command(name="add", help="Add an OpenPGP key.")
-def app_keys_add(path: str, committees: str = "", /) -> None:
+@APP_KEY.command(name="add", help="Add an OpenPGP key.")
+def app_key_add(path: str, committees: str = "", /) -> None:
selected_committee_names = []
if committees:
selected_committee_names[:] = committees.split(",")
@@ -750,21 +775,21 @@ def app_keys_add(path: str, committees: str = "", /) ->
None:
print(keys_add.fingerprint)
-@APP_KEYS.command(name="delete", help="Delete an OpenPGP key.")
-def app_keys_delete(fingerprint: str, /) -> None:
+@APP_KEY.command(name="delete", help="Delete an OpenPGP key.")
+def app_key_delete(fingerprint: str, /) -> None:
keys_delete_args = models.api.KeyDeleteArgs(fingerprint=fingerprint)
keys_delete = api_key_delete(keys_delete_args)
print(keys_delete.success)
-@APP_KEYS.command(name="get", help="Get an OpenPGP key.")
-def app_keys_get(fingerprint: str, /) -> None:
+@APP_KEY.command(name="get", help="Get an OpenPGP key.")
+def app_key_get(fingerprint: str, /) -> None:
keys_get = api_key_get(fingerprint)
print(keys_get.key.model_dump_json(indent=None))
-@APP_KEYS.command(name="upload", help="Upload a KEYS file.")
-def app_keys_upload(path: str, selected_committee_name: str, /) -> None:
+@APP_KEY.command(name="upload", help="Upload a KEYS file.")
+def app_key_upload(path: str, selected_committee_name: str, /) -> None:
# selected_committee_names = []
# if selected_committees:
# selected_committee_names[:] = selected_committees.split(",")
@@ -777,8 +802,8 @@ def app_keys_upload(path: str, selected_committee_name:
str, /) -> None:
print(f"Failed to upload {keys_upload.error_count} keys.")
-@APP_KEYS.command(name="user", help="List OpenPGP keys for a user.")
-def app_keys_user(asf_uid: str | None = None) -> None:
+@APP_KEY.command(name="user", help="List OpenPGP keys for a user.")
+def app_key_user(asf_uid: str | None = None) -> None:
if asf_uid is None:
with config_lock() as config:
asf_uid = config_get(config, ["asf", "uid"])
@@ -1428,12 +1453,13 @@ def show_warning(message: str) -> None:
def subcommands_register(app: cyclopts.App) -> None:
- app.command(APP_CHECKS)
+ app.command(APP_CHECK)
app.command(APP_CONFIG)
app.command(APP_DEV)
app.command(APP_DRAFT)
+ app.command(APP_IGNORE)
app.command(APP_JWT)
- app.command(APP_KEYS)
+ app.command(APP_KEY)
app.command(APP_RELEASE)
app.command(APP_SSH)
app.command(APP_VOTE)
diff --git a/src/atrclient/models/api.py b/src/atrclient/models/api.py
index 009ae07..a0294cd 100644
--- a/src/atrclient/models/api.py
+++ b/src/atrclient/models/api.py
@@ -34,24 +34,6 @@ class ResultsTypeError(TypeError):
pass
-class ChecksIgnoreAddArgs(schema.Strict):
- committee_name: str = schema.Field(..., **example("example"))
- release_glob: str | None = schema.Field(default=None,
**example("example-0.0.*"))
- revision_number: str | None = schema.Field(default=None,
**example("00001"))
- checker_glob: str | None = schema.Field(default=None,
**example("atr.tasks.checks.license.files"))
- primary_rel_path_glob: str | None = schema.Field(default=None,
**example("apache-example-0.0.1-*.tar.gz"))
- member_rel_path_glob: str | None = schema.Field(default=None,
**example("apache-example-0.0.1/*.xml"))
- status: sql.CheckResultStatusIgnore | None = schema.Field(
- default=None, **example(sql.CheckResultStatusIgnore.FAILURE)
- )
- message_glob: str | None = schema.Field(default=None, **example("sha512
matches for apache-example-0.0.1/*.xml"))
-
-
-class ChecksIgnoreAddResults(schema.Strict):
- endpoint: Literal["/checks/ignore/add"] = schema.Field(alias="endpoint")
- success: Literal[True] = schema.Field(..., **example(True))
-
-
class ChecksListResults(schema.Strict):
endpoint: Literal["/checks/list"] = schema.Field(alias="endpoint")
checks: Sequence[sql.CheckResult]
@@ -89,6 +71,39 @@ class CommitteesListResults(schema.Strict):
committees: Sequence[sql.Committee]
+class IgnoreAddArgs(schema.Strict):
+ committee_name: str = schema.Field(..., **example("example"))
+ release_glob: str | None = schema.Field(default=None,
**example("example-0.0.*"))
+ revision_number: str | None = schema.Field(default=None,
**example("00001"))
+ checker_glob: str | None = schema.Field(default=None,
**example("atr.tasks.checks.license.files"))
+ primary_rel_path_glob: str | None = schema.Field(default=None,
**example("apache-example-0.0.1-*.tar.gz"))
+ member_rel_path_glob: str | None = schema.Field(default=None,
**example("apache-example-0.0.1/*.xml"))
+ status: sql.CheckResultStatusIgnore | None = schema.Field(
+ default=None, **example(sql.CheckResultStatusIgnore.FAILURE)
+ )
+ message_glob: str | None = schema.Field(default=None, **example("sha512
matches for apache-example-0.0.1/*.xml"))
+
+
+class IgnoreAddResults(schema.Strict):
+ endpoint: Literal["/ignore/add"] = schema.Field(alias="endpoint")
+ success: Literal[True] = schema.Field(..., **example(True))
+
+
+class IgnoreDeleteArgs(schema.Strict):
+ committee: str = schema.Field(..., **example("example"))
+ id: int = schema.Field(..., **example(1))
+
+
+class IgnoreDeleteResults(schema.Strict):
+ endpoint: Literal["/ignore/delete"] = schema.Field(alias="endpoint")
+ success: Literal[True] = schema.Field(..., **example(True))
+
+
+class IgnoreListResults(schema.Strict):
+ endpoint: Literal["/ignore/list"] = schema.Field(alias="endpoint")
+ ignores: Sequence[sql.CheckResultIgnore]
+
+
class JwtCreateArgs(schema.Strict):
asfuid: str = schema.Field(..., **example("user"))
pat: str = schema.Field(...,
**example("8M5t4GCU63EdOy4NNXgXn7o-bc-muK8TRg5W-DeBaWY"))
@@ -399,13 +414,15 @@ class VoteTabulateResults(schema.Strict):
# This is for *Results classes only
# We do NOT put *Args classes here
Results = Annotated[
- ChecksIgnoreAddResults
- | ChecksListResults
+ ChecksListResults
| ChecksOngoingResults
| CommitteeGetResults
| CommitteeKeysResults
| CommitteeProjectsResults
| CommitteesListResults
+ | IgnoreAddResults
+ | IgnoreDeleteResults
+ | IgnoreListResults
| JwtCreateResults
| KeyAddResults
| KeyDeleteResults
@@ -449,13 +466,15 @@ def validator[T](t: type[T]) -> Callable[[Any], T]:
return validate
-validate_checks_ignore_add = validator(ChecksIgnoreAddResults)
validate_checks_list = validator(ChecksListResults)
validate_checks_ongoing = validator(ChecksOngoingResults)
validate_committee_get = validator(CommitteeGetResults)
validate_committee_keys = validator(CommitteeKeysResults)
validate_committee_projects = validator(CommitteeProjectsResults)
validate_committees_list = validator(CommitteesListResults)
+validate_ignore_add = validator(IgnoreAddResults)
+validate_ignore_delete = validator(IgnoreDeleteResults)
+validate_ignore_list = validator(IgnoreListResults)
validate_jwt_create = validator(JwtCreateResults)
validate_key_add = validator(KeyAddResults)
validate_key_delete = validator(KeyDeleteResults)
diff --git a/src/atrclient/models/sql.py b/src/atrclient/models/sql.py
index d58121c..e77d213 100644
--- a/src/atrclient/models/sql.py
+++ b/src/atrclient/models/sql.py
@@ -737,6 +737,10 @@ class CheckResultIgnore(sqlmodel.SQLModel, table=True):
)
message_glob: str | None = sqlmodel.Field(**example("sha512 matches for
apache-example-0.0.1/*.xml"))
+ def model_post_init(self, _context):
+ if isinstance(self.created, str):
+ self.created =
datetime.datetime.fromisoformat(self.created.rstrip("Z"))
+
# DistributionChannel: Project
class DistributionChannel(sqlmodel.SQLModel, table=True):
diff --git a/tests/cli_keys.t b/tests/cli_keys.t
index dce0ce8..02226a6 100644
--- a/tests/cli_keys.t
+++ b/tests/cli_keys.t
@@ -13,7 +13,7 @@ $ atr dev pat
$ atr set tokens.pat <!pat!>
Set tokens.pat to "<!pat!>".
-$ atr keys user
+$ atr key user
<.etc.>
$ atr dev pwd
@@ -22,14 +22,14 @@ $ atr dev pwd
<# write a test key to tooling-public-test.asc #>
$ atr dev key
-$ atr keys add tooling-public-test.asc
+$ atr key add tooling-public-test.asc
E35604DD9E2892E5465B3D8A203F105A7B33A64F
-$ atr keys get E35604DD9E2892E5465B3D8A203F105A7B33A64F
+$ atr key get E35604DD9E2892E5465B3D8A203F105A7B33A64F
<.skip.>e35604dd9e2892e5465b3d8a203f105a7b33a64f<.skip.>example.invalid<.skip.>
-* atr keys delete E35604DD9E2892E5465B3D8A203F105A7B33A64F
+* atr key delete E35604DD9E2892E5465B3D8A203F105A7B33A64F
<.etc.>
-$ atr keys upload tooling-public-test.asc tooling
+$ atr key upload tooling-public-test.asc tooling
<.etc.>
diff --git a/tests/cli_workflow.t b/tests/cli_workflow.t
index 927426b..ce762d4 100644
--- a/tests/cli_workflow.t
+++ b/tests/cli_workflow.t
@@ -32,14 +32,14 @@ $ atr config path
$ atr upload tooling-test-example 0.3+cli atr-client.conf <!config_rel_path!>
<.skip.>created<.skip.>
-$ atr checks wait tooling-test-example 0.3+cli -i 25
+$ atr check wait tooling-test-example 0.3+cli -i 25
Checks completed.
-$ atr checks status tooling-test-example 0.3+cli
+$ atr check status tooling-test-example 0.3+cli
Total checks: 1
warning: 1
-$ atr checks status tooling-test-example 0.3+cli 00002
+$ atr check status tooling-test-example 0.3+cli 00002
Total checks: 1
warning: 1
diff --git a/tests/test_all.py b/tests/test_all.py
index a42bca4..ffb28eb 100755
--- a/tests/test_all.py
+++ b/tests/test_all.py
@@ -75,7 +75,7 @@ def test_app_checks_status_non_draft_phase(
},
)
- client.app_checks_status("test-project", "2.3.0", "00001")
+ client.app_check_status("test-project", "2.3.0", "00001")
captured = capsys.readouterr()
assert "Checks are not applicable for this release phase." in
captured.out
@@ -150,7 +150,7 @@ def test_app_checks_status_verbose(capsys:
pytest.CaptureFixture[str], fixture_c
mock.get(release_url, status=200, payload=release_payload)
mock.get(checks_url, status=200, payload=checks_payload)
- client.app_checks_status("test-project", "2.3.1", "00003",
verbose=True)
+ client.app_check_status("test-project", "2.3.1", "00003", verbose=True)
captured = capsys.readouterr()
assert "(top-level" in captured.out
diff --git a/uv.lock b/uv.lock
index 3adf94c..a3c74dc 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,7 +2,7 @@ version = 1
requires-python = ">=3.13"
[options]
-exclude-newer = "2025-07-29T19:43:00Z"
+exclude-newer = "2025-07-30T14:48:00Z"
[[package]]
name = "aiohappyeyeballs"
@@ -83,7 +83,7 @@ wheels = [
[[package]]
name = "apache-trusted-releases"
-version = "0.20250729.1943"
+version = "0.20250730.1448"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]