Skip to content

Commit de4eec2

Browse files
committed
update changelog
1 parent 8041dc5 commit de4eec2

File tree

6 files changed

+48
-12
lines changed

6 files changed

+48
-12
lines changed

docs/changelog.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22
ChangeLog
33
#########
44

5+
******************
6+
0.3.0 (2025-12-26)
7+
******************
8+
9+
* Tutorials can now be configured to pass a clear environment to all processes.
10+
* Tutorials can now configure additional environment variables passed to all processes.
11+
* Single commands can now update the environment for all subsequent commands. Values are rendered as
12+
templates, so you can add (parts of) the output of a command to the environment by combining a test for
13+
the command output that uses a named pattern in a regular expression for the output.
14+
* ``parts.{commands}.{command}.run.{chdir}`` is now a template. This allows you to change the directory based
15+
on the output of a previous command.
16+
* Bugfix: Individual commands marked as skipped for documentation, are now actually skipped.
17+
518
******************
619
0.2.0 (2025-12-23)
720
******************

docs/spelling_wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ hostname
77
cwd
88
backend
99
reStructuredText
10+
bugfix

structured_tutorials/runners/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def __init__(
5353
self.environment = {}
5454
else:
5555
self.environment = os.environ.copy()
56-
self.environment.update(tutorial.configuration.run.environment)
56+
self.environment.update(tutorial.configuration.run.environment) # type: ignore[arg-type] # temporary
5757
self.environment = {k: self.render(v) for k, v in self.environment.items() if v is not None}
5858

5959
self.cleanup: list[CleanupCommandModel] = []
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
configuration:
2+
run:
3+
context:
4+
VALUE: /does/not/exist
5+
parts:
6+
- commands:
7+
- command: ls
8+
run:
9+
chdir: "{{ VALUE }}"

tests/runners/local/commands/test_environment.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ def test_simple_environment(fp: FakeProcess, runner: LocalTutorialRunner) -> Non
3636
recorder = fp.register("ls")
3737
assert runner.environment == ENV
3838
runner.run()
39-
assert recorder.calls[0].kwargs["env"] == ENV
39+
actual_kwargs = recorder.calls[0].kwargs
40+
assert actual_kwargs is not None
41+
assert actual_kwargs["env"] == ENV
4042

4143

4244
@pytest.mark.tutorial("command-clear-single-environment-variable")
@@ -46,7 +48,9 @@ def test_clear_single_environment_variable(fp: FakeProcess, runner: LocalTutoria
4648
recorder = fp.register("ls")
4749
assert runner.environment == {"ENV_2": "VALUE_2"}
4850
runner.run()
49-
assert recorder.calls[0].kwargs["env"] == {"ENV_2": "VALUE_2"}
51+
actual_kwargs = recorder.calls[0].kwargs
52+
assert actual_kwargs is not None
53+
assert actual_kwargs["env"] == {"ENV_2": "VALUE_2"}
5054

5155

5256
@pytest.mark.tutorial("command-clear-environment-globally")
@@ -58,10 +62,10 @@ def test_global_environment(fp: FakeProcess, runner: LocalTutorialRunner) -> Non
5862
recorder3 = fp.register('echo "3: $KEY"')
5963
recorder4 = fp.register('echo "4: $KEY"')
6064
runner.run()
61-
assert recorder1.calls[0].kwargs["env"] == {}
62-
assert recorder2.calls[0].kwargs["env"] == {"KEY": "OTHER VALUE", "KEY2": "VALUE2"}
63-
assert recorder3.calls[0].kwargs["env"] == {"KEY": "1: VALUE"}
64-
assert recorder4.calls[0].kwargs["env"] == {}
65+
assert recorder1.calls[0].kwargs["env"] == {} # type: ignore[index]
66+
assert recorder2.calls[0].kwargs["env"] == {"KEY": "OTHER VALUE", "KEY2": "VALUE2"} # type: ignore[index]
67+
assert recorder3.calls[0].kwargs["env"] == {"KEY": "1: VALUE"} # type: ignore[index]
68+
assert recorder4.calls[0].kwargs["env"] == {} # type: ignore[index]
6569

6670

6771
@pytest.mark.tutorial("command-env-variable-for-single-command")

tests/runners/local/test_command.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import io
77
import os
88
import subprocess
9-
from pathlib import Path
9+
from typing import Any
1010
from unittest import mock
1111

1212
import pytest
@@ -64,7 +64,7 @@ def test_command_as_list(fp: FakeProcess, runner: LocalTutorialRunner) -> None:
6464
recorder_test = fp.register(["ls", "test with spaces"])
6565
recorder_cleanup = fp.register(["ls", "cleanup with spaces"])
6666
runner.run()
67-
expected = {"shell": False, "stdin": None, "stderr": None, "stdout": None, "env": {}}
67+
expected: dict[str, Any] = {"shell": False, "stdin": None, "stderr": None, "stdout": None, "env": {}}
6868
assert recorder_main.calls[0].kwargs == expected
6969
assert recorder_test.calls[0].kwargs == expected
7070
assert recorder_cleanup.calls[0].kwargs == expected
@@ -85,7 +85,16 @@ def test_command_with_chdir(fp: FakeProcess, runner: LocalTutorialRunner) -> Non
8585
fp.register("ls")
8686
with mock.patch("os.chdir", autospec=True) as mock_chdir:
8787
runner.run()
88-
mock_chdir.assert_called_once_with(Path("/does/not/exist"))
88+
mock_chdir.assert_called_once_with("/does/not/exist")
89+
90+
91+
@pytest.mark.tutorial("command-with-chdir-template")
92+
def test_command_with_chdir_with_template(fp: FakeProcess, runner: LocalTutorialRunner) -> None:
93+
"""Test changing the working directory after a command."""
94+
fp.register("ls")
95+
with mock.patch("os.chdir", autospec=True) as mock_chdir:
96+
runner.run()
97+
mock_chdir.assert_called_once_with("/does/not/exist")
8998

9099

91100
@pytest.mark.tutorial("command-stdin")
@@ -112,7 +121,7 @@ def test_command_hide_output(fp: FakeProcess, runner: LocalTutorialRunner) -> No
112121
recorder_test = fp.register("ls test")
113122
recorder_cleanup = fp.register("ls cleanup")
114123
runner.run()
115-
expected = {
124+
expected: dict[str, Any] = {
116125
"shell": True,
117126
"stdin": None,
118127
"stderr": subprocess.DEVNULL,
@@ -131,7 +140,7 @@ def test_command_capture_output(
131140
"""Test running a commands with capturing the output."""
132141
recorder = fp.register("echo foo bar bla", stdout="foo bar bla", stderr="foo bla bla")
133142
runner.run()
134-
expected = {
143+
expected: dict[str, Any] = {
135144
"shell": True,
136145
"stdin": None,
137146
"stderr": subprocess.PIPE,

0 commit comments

Comments
 (0)