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 9c02286 Add a test for getting checks, and fix some issues
9c02286 is described below
commit 9c02286ce1012d3411abcd1f729f32039a70c915
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Jul 14 17:28:17 2025 +0100
Add a test for getting checks, and fix some issues
---
pyproject.toml | 4 ++--
src/atrclient/client.py | 59 +++++++++++++++++++++++++------------------------
tests/cli_workflow.t | 9 ++++++--
tests/test_all.py | 32 ++++++++++-----------------
uv.lock | 4 ++--
5 files changed, 53 insertions(+), 55 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 206a98e..d40b09e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ build-backend = "hatchling.build"
[project]
name = "apache-trusted-releases"
-version = "0.20250714.1419"
+version = "0.20250714.1626"
description = "ATR CLI and Python API"
readme = "README.md"
requires-python = ">=3.13"
@@ -72,4 +72,4 @@ select = [
]
[tool.uv]
-exclude-newer = "2025-07-14T14:19:00Z"
+exclude-newer = "2025-07-14T16:26:00Z"
diff --git a/src/atrclient/client.py b/src/atrclient/client.py
index 93debbb..ff83aeb 100755
--- a/src/atrclient/client.py
+++ b/src/atrclient/client.py
@@ -112,29 +112,18 @@ def app_checks_failures(
def app_checks_status(
project: str,
version: str,
- revision: str,
/,
+ revision: str | None = None,
verbose: Annotated[bool, cyclopts.Parameter(alias="-v", name="--verbose")]
= False,
) -> None:
jwt_value = config_jwt_usable()
host, verify_ssl = config_host_get()
- release_url = f"https://{host}/api/releases/{project}"
- releases_result = asyncio.run(web_get_public(release_url, verify_ssl))
- if not is_json_dict(releases_result):
- show_error_and_exit(f"Unexpected API response: {releases_result}")
-
- target_release = None
- releases_result_data = releases_result.get("data", [])
- if not is_json_list_of_dict(releases_result_data):
- show_error_and_exit(f"Unexpected API response: {releases_result_data}")
- for release in releases_result_data:
- if release.get("version") == version:
- target_release = release
- break
-
- if target_release is None:
- show_error_and_exit(f"Release {project}-{version} not found.")
+ release_url = f"https://{host}/api/releases/{project}/{version}"
+ target_release = asyncio.run(web_get_public(release_url, verify_ssl))
+ # TODO: Handle the not found case better
+ if not is_json_dict(target_release):
+ show_error_and_exit(f"Unexpected API response: {target_release}")
phase = target_release.get("phase")
if phase != "release_candidate_draft":
@@ -142,6 +131,14 @@ def app_checks_status(
print("Checks are only performed during the draft phase.")
return
+ if revision is None:
+ latest_revision_number = target_release.get("latest_revision_number")
+ if latest_revision_number is None:
+ show_error_and_exit("No revision number found.")
+ if not isinstance(latest_revision_number, str):
+ show_error_and_exit(f"Unexpected API response:
{latest_revision_number}")
+ revision = latest_revision_number
+
url = f"https://{host}/api/checks/list/{project}/{version}/{revision}"
results = asyncio.run(web_get(url, jwt_value, verify_ssl))
@@ -156,26 +153,30 @@ def app_checks_wait(
version: str,
/,
revision: str | None = None,
- timeout: Annotated[int, cyclopts.Parameter(alias="-t", name="--timeout")]
= 60,
+ timeout: Annotated[float, cyclopts.Parameter(alias="-t",
name="--timeout")] = 60,
interval: Annotated[int, cyclopts.Parameter(alias="-i",
name="--interval")] = 500,
) -> None:
- if interval < 500:
- show_error_and_exit("Interval must be at least 500ms.")
- if (interval / 1000) > timeout:
+ host, verify_ssl = config_host_get()
+ if verify_ssl is True:
+ if interval < 500:
+ show_error_and_exit("Interval must be at least 500ms.")
+ interval_seconds = interval / 1000
+ if interval_seconds > timeout:
show_error_and_exit("Interval must be less than timeout.")
jwt_value = config_jwt_usable()
- host, verify_ssl = config_host_get()
while True:
- url =
f"https://{host}/api/checks/ongoing/{project}/{version}/{revision}"
- count = asyncio.run(web_get(url, jwt_value, verify_ssl))
+ url = f"https://{host}/api/checks/ongoing/{project}/{version}"
+ if revision is not None:
+ url += f"/{revision}"
+ result = asyncio.run(web_get(url, jwt_value, verify_ssl))
try:
- count = models.api.ResultCount.model_validate(count)
+ result_count = models.api.ResultCount.model_validate(result)
except pydantic.ValidationError as e:
- show_error_and_exit(f"Unexpected API response: {count}\n{e}")
- if count.count == 0:
+ show_error_and_exit(f"Unexpected API response: {result}\n{e}")
+ if result_count.count == 0:
break
- time.sleep(interval / 1000)
- timeout -= 1
+ time.sleep(interval_seconds)
+ timeout -= interval_seconds
if timeout <= 0:
show_error_and_exit("Timeout waiting for checks to complete.")
print("Checks completed.")
diff --git a/tests/cli_workflow.t b/tests/cli_workflow.t
index 398634d..a4fc744 100644
--- a/tests/cli_workflow.t
+++ b/tests/cli_workflow.t
@@ -13,7 +13,7 @@ $ atr dev pat
$ atr set tokens.pat <!pat!>
Set tokens.pat to "<!pat!>".
-<# Reset any existing draft, ignoring errors. #>
+<# Delete any existing draft, ignoring errors. #>
* atr draft delete tooling-test-example 0.3+cli
<.etc.>
@@ -26,8 +26,13 @@ $ 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
+$ atr checks wait tooling-test-example 0.3+cli -i 25
Checks completed.
+$ atr checks status tooling-test-example 0.3+cli
+Total checks: 1
+ warning: 1
+
+<# Tidy up. #>
* atr draft delete tooling-test-example 0.3+cli
<.etc.>
diff --git a/tests/test_all.py b/tests/test_all.py
index c5d2f9c..b7c76fc 100755
--- a/tests/test_all.py
+++ b/tests/test_all.py
@@ -51,22 +51,17 @@ def test_app_checks_status_non_draft_phase(
client.app_set("atr.host", "example.invalid")
client.app_set("tokens.jwt", "dummy_jwt_token")
- releases_url = "https://example.invalid/api/releases/test-project"
+ releases_url = "https://example.invalid/api/releases/test-project/2.3.0"
with aioresponses.aioresponses() as mock:
mock.get(
releases_url,
status=200,
payload={
- "data": [
- {
- "version": "2.3.0",
- "phase": "release",
- "created": "2024-07-04T00:00:00.000000Z",
- "latest_revision_number": "00001",
- }
- ],
- "count": 1,
+ "version": "2.3.0",
+ "phase": "release",
+ "created": "2024-07-04T00:00:00.000000Z",
+ "latest_revision_number": "00001",
},
)
@@ -81,19 +76,14 @@ def test_app_checks_status_verbose(capsys:
pytest.CaptureFixture[str], fixture_c
client.app_set("atr.host", "example.invalid")
client.app_set("tokens.jwt", "dummy_jwt_token")
- release_url = "https://example.invalid/api/releases/test-project"
+ release_url = "https://example.invalid/api/releases/test-project/2.3.1"
checks_url =
"https://example.invalid/api/checks/list/test-project/2.3.1/00003"
release_payload = {
- "data": [
- {
- "version": "2.3.1",
- "phase": "release_candidate_draft",
- "created": "2025-01-01T00:00:00.000000Z",
- "latest_revision_number": "00003",
- }
- ],
- "count": 1,
+ "version": "2.3.1",
+ "phase": "release_candidate_draft",
+ "created": "2025-01-01T00:00:00.000000Z",
+ "latest_revision_number": "00003",
}
checks_payload = [
@@ -259,6 +249,8 @@ def transcript_capture(
with open(transcript_path, encoding="utf-8") as f:
for line in f:
line = line.rstrip("\n")
+ if line == "<.exit.>":
+ return
if captures:
line = REGEX_USE.sub(lambda m: captures[m.group(1)], line)
line = REGEX_COMMENT.sub("", line)
diff --git a/uv.lock b/uv.lock
index 04253fd..74ad27b 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,7 +2,7 @@ version = 1
requires-python = ">=3.13"
[options]
-exclude-newer = "2025-07-14T14:19:00Z"
+exclude-newer = "2025-07-14T16:26:00Z"
[[package]]
name = "aiohappyeyeballs"
@@ -83,7 +83,7 @@ wheels = [
[[package]]
name = "apache-trusted-releases"
-version = "0.20250714.1419"
+version = "0.20250714.1626"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]