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 d47e2b1 Improve the transcript test format
d47e2b1 is described below
commit d47e2b1685aa5a38ea4de49f7c4a4319d7d69e61
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Jul 10 19:55:12 2025 +0100
Improve the transcript test format
---
pyproject.toml | 4 ++--
src/atrclient/client.py | 14 ++++++++++++++
tests/cli_config.t | 16 ++++++++--------
tests/cli_version.t | 2 +-
tests/test_all.py | 39 ++++++++++++++++++++++++++++++++-------
uv.lock | 4 ++--
6 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 597ead7..540e8c2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ build-backend = "hatchling.build"
[project]
name = "apache-trusted-releases"
-version = "0.20250710.1806"
+version = "0.20250710.1854"
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-10T18:06:00Z"
+exclude-newer = "2025-07-10T18:54:00Z"
diff --git a/src/atrclient/client.py b/src/atrclient/client.py
index 9f13868..f996750 100755
--- a/src/atrclient/client.py
+++ b/src/atrclient/client.py
@@ -221,6 +221,20 @@ def app_dev_stamp() -> None:
print("Updated tests/cli_version.t.")
+@APP_DEV.command(name="token", help="Generate a random alphabetical token.")
+def app_dev_token() -> None:
+ import secrets
+
+ label = ""
+ # int(math.log2(26 ** 16)) == 75
+ while len(label) < 16:
+ i = secrets.randbits(5)
+ # Do not use modulo here
+ if i < 26:
+ label += chr(i + 97)
+ print(label)
+
+
@APP_DRAFT.command(name="delete", help="Delete a draft release.")
def app_draft_delete(project: str, version: str, /) -> None:
jwt_value = config_jwt_usable()
diff --git a/tests/cli_config.t b/tests/cli_config.t
index 86cfbbd..8b04b37 100644
--- a/tests/cli_config.t
+++ b/tests/cli_config.t
@@ -1,13 +1,13 @@
$ atr dev env
-ATR_CLIENT_CONFIG_PATH="<!CONFIG_PATH!>"
-<!...!>
+ATR_CLIENT_CONFIG_PATH="<.skip.>"
+<.etc.>
! atr config file
-<!stderr!>
+<.stderr.>
atr: error: No configuration file found.
$ atr config path
-/<!ROOT_REL_PATH!>
+/<.skip.>
$ atr set asf.uid example
Set asf.uid to "example".
@@ -17,13 +17,13 @@ asf:
uid: example
! atr drop --path asf.uid
-╭─ Error
──────────────────────────────────────────────────────────────────────╮
-│ Unknown option: "--path".
│
-╰──────────────────────────────────────────────────────────────────────────────╯
+<.skip.>
+<.skip.>Unknown option: "--path"<.skip.>
+<.etc.>
$ atr drop asf.uid
Removed asf.uid.
! atr config file
-<!stderr!>
+<.stderr.>
atr: error: No configuration file found.
diff --git a/tests/cli_version.t b/tests/cli_version.t
index de10014..2c98271 100644
--- a/tests/cli_version.t
+++ b/tests/cli_version.t
@@ -1,2 +1,2 @@
$ atr --version
-0.20250710.1806
+0.20<.skip.>.<.skip.>
diff --git a/tests/test_all.py b/tests/test_all.py
index b9af31e..57c0607 100755
--- a/tests/test_all.py
+++ b/tests/test_all.py
@@ -202,38 +202,63 @@ def test_cli_transcripts(
script_runner: pytest_console_scripts.ScriptRunner,
fixture_config_env: pathlib.Path,
) -> None:
- r_variable = re.compile(r"<!([A-Z_]+)!>")
+ captures = {}
+ r_capture = re.compile(r"<\?([A-Za-z_]+)\?>|<.(skip).>|(.+?)")
+ r_use = re.compile(r"<!([A-Za-z_]+)!>")
env = os.environ.copy()
transcript_config_path = fixture_config_env
+
# transcript_config_path =
fixture_config_env.with_suffix(f".{transcript_path.name}")
# if transcript_config_path.exists():
# pytest.fail(f"Transcript config file already exists:
{transcript_config_path}")
+ def substitute_uses(captures: dict[str, str], line: str) -> str:
+ return r_use.sub(lambda m: captures[m.group(1)], line)
+
env["ATR_CLIENT_CONFIG_PATH"] = str(transcript_config_path)
with open(transcript_path, "r", encoding="utf-8") as f:
actual_output = []
for line in f:
line = line.rstrip("\n")
+ if captures:
+ line = substitute_uses(captures, line)
if line.startswith("$ ") or line.startswith("! "):
expected_code = 0 if line.startswith("$ ") else 1
command = line[2:]
if not command.startswith("atr"):
pytest.fail(f"Command does not start with 'atr':
{command}")
return
+ print(f"Running: {command}")
result = script_runner.run(shlex.split(command), env=env)
- assert result.returncode == expected_code
+ assert result.returncode == expected_code, (
+ f"Command {command!r} returned {result.returncode}"
+ )
actual_output[:] = result.stdout.splitlines()
if result.stderr:
- actual_output.append("<!stderr!>")
+ actual_output.append("<.stderr.>")
actual_output.extend(result.stderr.splitlines())
elif actual_output:
- if line == "<!...!>":
+ if line == "<.etc.>":
actual_output[:] = []
continue
actual_output_line = actual_output.pop(0)
- # Replace variables with (?P<variable>.*?)
- line_pattern = r_variable.sub(r"(?P<\1>.*?)", line)
- if line_pattern != line:
+ # Replace captures with (?P<name>.*?)
+ use_regex = False
+
+ def capture_sub(m: re.Match[str]) -> str:
+ nonlocal use_regex
+ if m.group(1):
+ use_regex = True
+ return f"(?P<{m.group(1)}>.*?)"
+ if m.group(2) == "skip":
+ use_regex = True
+ return "(.*?)"
+ return re.escape(m.group(3))
+
+ line_pattern = r"^" + r_capture.sub(capture_sub, line) + r"$"
+ if use_regex:
success = re.match(line_pattern, actual_output_line)
+ if success:
+ captures.update(success.groupdict())
else:
success = actual_output_line == line
if not success:
diff --git a/uv.lock b/uv.lock
index 20dd570..439b332 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,7 +2,7 @@ version = 1
requires-python = ">=3.13"
[options]
-exclude-newer = "2025-07-10T18:06:00Z"
+exclude-newer = "2025-07-10T18:54:00Z"
[[package]]
name = "aiohappyeyeballs"
@@ -74,7 +74,7 @@ wheels = [
[[package]]
name = "apache-trusted-releases"
-version = "0.20250710.1806"
+version = "0.20250710.1854"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]