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 24bb671  Add transcript testing
24bb671 is described below

commit 24bb671f3358e68fd2ddb48068fc7e57a87986ca
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Jul 10 15:28:35 2025 +0100

    Add transcript testing
---
 pyproject.toml          |  4 ++--
 src/atrclient/client.py | 29 +++++++++++++++++++++++++----
 tests/cli_version.t     |  2 ++
 tests/test_all.py       | 37 +++++++++++++++++++++++++++++++++++++
 uv.lock                 |  4 ++--
 5 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/pyproject.toml b/pyproject.toml
index 1c45dc6..2826c92 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ build-backend = "hatchling.build"
 
 [project]
 name            = "apache-trusted-releases"
-version         = "0.20250710.1345"
+version         = "0.20250710.1426"
 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-10T13:45:00Z"
+exclude-newer = "2025-07-10T14:26:00Z"
diff --git a/src/atrclient/client.py b/src/atrclient/client.py
index 6f67f7e..3a0b88f 100755
--- a/src/atrclient/client.py
+++ b/src/atrclient/client.py
@@ -197,6 +197,17 @@ def app_dev_stamp() -> None:
     )
     LOGGER.info("Updated version." if version_updated else "Did not update 
version.")
 
+    path = pathlib.Path("tests/cli_version.t")
+    if not path.exists():
+        LOGGER.warning("tests/cli_version.t not found.")
+        return
+    text_v1 = path.read_text(encoding="utf-8")
+    text_v2 = re.sub(r"0\.\d{8}\.\d{4}", v, text_v1)
+    version_updated = not (text_v1 == text_v2)
+    if version_updated:
+        path.write_text(text_v2, "utf-8")
+        LOGGER.info("Updated tests/cli_version.t.")
+
 
 @APP.command(name="docs", help="Show comprehensive CLI documentation in 
Markdown.")
 def app_docs() -> None:
@@ -683,6 +694,18 @@ def documentation_to_markdown(
     return markdown
 
 
+def initialise() -> None:
+    # We do this because pytest_console_scripts.ScriptRunner invokes main 
multiple times
+    APP.version = VERSION
+    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+    logging.basicConfig(level=logging.INFO, format="%(message)s")
+    subcommands_register(APP)
+
+
+def initialised() -> bool:
+    return APP.version == VERSION
+
+
 def iso_to_human(ts: str) -> str:
     dt = datetime.datetime.fromisoformat(ts.rstrip("Z"))
     if dt.tzinfo is None:
@@ -691,10 +714,8 @@ def iso_to_human(ts: str) -> str:
 
 
 def main() -> None:
-    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
-    logging.basicConfig(level=logging.INFO, format="%(message)s")
-    subcommands_register(APP)
-    APP.version = VERSION
+    if not initialised():
+        initialise()
     # if "PYTEST_CURRENT_TEST" in os.environ:
     #     # "Cyclopts application invoked without tokens"
     #     pass
diff --git a/tests/cli_version.t b/tests/cli_version.t
new file mode 100644
index 0000000..2fb95e8
--- /dev/null
+++ b/tests/cli_version.t
@@ -0,0 +1,2 @@
+$ atr --version
+0.20250710.1426
diff --git a/tests/test_all.py b/tests/test_all.py
index 16119f3..83bcaad 100755
--- a/tests/test_all.py
+++ b/tests/test_all.py
@@ -18,6 +18,7 @@
 # TODO: Use transcript style script testing
 
 from __future__ import annotations
+import shlex
 
 import atrclient.client as client
 import pathlib
@@ -28,6 +29,12 @@ import pytest
 import pytest_console_scripts
 
 
+def decorator_transcript_file_paths() -> list[pathlib.Path]:
+    parent = pathlib.Path(__file__).parent
+    paths = list(parent.glob("*.t"))
+    return paths
+
+
 def test_app_checks_status_non_draft_phase(
     capsys: pytest.CaptureFixture[str], fixture_config_env: pathlib.Path
 ) -> None:
@@ -182,6 +189,36 @@ def test_cli_version(script_runner: 
pytest_console_scripts.ScriptRunner) -> None
     assert result.stderr == ""
 
 
[email protected](
+    "transcript_path", decorator_transcript_file_paths(), ids=lambda p: p.name
+)
+def test_cli_transcripts(
+    transcript_path: pathlib.Path, script_runner: 
pytest_console_scripts.ScriptRunner
+) -> None:
+    with open(transcript_path, "r", encoding="utf-8") as f:
+        actual_stdout = []
+        for line in f:
+            line = line.rstrip("\n")
+            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
+                result = script_runner.run(shlex.split(command))
+                assert result.returncode == expected_code
+                actual_stdout[:] = result.stdout.splitlines()
+            elif actual_stdout:
+                actual_stdout_line = actual_stdout.pop(0)
+                if actual_stdout_line != line:
+                    pytest.fail(f"Expected {line!r} but got 
{actual_stdout_line!r}")
+                    return
+            elif line:
+                pytest.fail(f"Unexpected line: {line!r}")
+                return
+        assert not actual_stdout
+
+
 def test_config_set_get_roundtrip() -> None:
     config: dict[str, Any] = {}
     client.config_set(config, ["abc", "pqr"], 123)
diff --git a/uv.lock b/uv.lock
index bbb5e38..5e59bf5 100644
--- a/uv.lock
+++ b/uv.lock
@@ -2,7 +2,7 @@ version = 1
 requires-python = ">=3.13"
 
 [options]
-exclude-newer = "2025-07-10T13:45:00Z"
+exclude-newer = "2025-07-10T14:26:00Z"
 
 [[package]]
 name = "aiohappyeyeballs"
@@ -74,7 +74,7 @@ wheels = [
 
 [[package]]
 name = "apache-trusted-releases"
-version = "0.20250710.1345"
+version = "0.20250710.1426"
 source = { editable = "." }
 dependencies = [
     { name = "aiohttp" },


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

Reply via email to