~
Release / Pre-release Check (push) Failing after 1m31s
Release / Build Artifacts (push) Has been skipped
Release / Publish to PyPI (push) Has been skipped
Release / Publish Release (push) Has been skipped

This commit is contained in:
2026-06-25 12:36:47 +08:00
parent 9e99a1f1ba
commit 0afdb54e5c
6 changed files with 334 additions and 18 deletions
+303
View File
@@ -194,3 +194,306 @@ class TestCommandReferences:
# Verify total layers
assert len(layers) == 4
def test_execution_order_multiple_original_tasks(self) -> None:
"""Should execute multiple original TaskSpecs in correct order."""
task1 = px.TaskSpec("task1", cmd=["echo", "1"])
task2 = px.TaskSpec("task2", cmd=["echo", "2"])
task3 = px.TaskSpec("task3", cmd=["echo", "3"])
task4 = px.TaskSpec("task4", cmd=["echo", "4"])
task5 = px.TaskSpec("task5", cmd=["echo", "5"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"cmd1": px.Graph.from_specs([task1]),
"cmd2": px.Graph.from_specs([task2]),
"all": px.Graph.from_specs(["cmd1", "cmd2", task3, task4, task5]),
},
)
# Check execution order through layers
layers = runner.graphs["all"].layers()
# Layer 1: task1 (cmd1)
assert "task1" in layers[0]
# Layer 2: task2 (cmd2)
assert "task2" in layers[1]
# Layer 3: task3 (first original TaskSpec)
assert "task3" in layers[2]
# Layer 4: task4 (second original TaskSpec)
assert "task4" in layers[3]
# Layer 5: task5 (third original TaskSpec)
assert "task5" in layers[4]
# Verify total layers
assert len(layers) == 5
def test_execution_order_with_internal_dependencies(self) -> None:
"""Should preserve internal dependencies within referenced commands."""
task1 = px.TaskSpec("task1", cmd=["echo", "1"])
task2 = px.TaskSpec("task2", cmd=["echo", "2"], depends_on=("task1",))
task3 = px.TaskSpec("task3", cmd=["echo", "3"])
task4 = px.TaskSpec("task4", cmd=["echo", "4"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"cmd1": px.Graph.from_specs([task1, task2]),
"cmd2": px.Graph.from_specs([task3]),
"all": px.Graph.from_specs(["cmd1", "cmd2", task4]),
},
)
# Check execution order through layers
layers = runner.graphs["all"].layers()
# Layer 1: task1
assert "task1" in layers[0]
# Layer 2: task2 (depends on task1)
assert "task2" in layers[1]
# Layer 3: task3 (cmd2, depends on task2)
assert "task3" in layers[2]
# Layer 4: task4 (original TaskSpec, depends on task3)
assert "task4" in layers[3]
# Verify total layers
assert len(layers) == 4
def test_execution_order_pymake_bump_scenario(self) -> None:
"""Should execute pymake bump command in correct order."""
# Simulate pymake bump scenario
git_clean = px.TaskSpec("git_clean", cmd=["echo", "clean"])
typecheck = px.TaskSpec("typecheck", cmd=["echo", "typecheck"])
lint = px.TaskSpec("lint", cmd=["echo", "lint"])
format_task = px.TaskSpec("format", cmd=["echo", "format"], depends_on=("lint",))
git_add_all = px.TaskSpec("git_add_all", cmd=["echo", "git add -A"])
bump = px.TaskSpec("bumpversion", cmd=["echo", "bumpversion -t"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"c": px.Graph.from_specs([git_clean]),
"tc": px.Graph.from_specs([typecheck, "lint"]),
"lint": px.Graph.from_specs([lint, format_task]),
"bump": px.Graph.from_specs(["c", "tc", git_add_all, bump]),
},
)
# Check execution order through layers
layers = runner.graphs["bump"].layers()
# Layer 1: git_clean (c)
assert "git_clean" in layers[0]
# Layer 2: lint (tc.lint, depends on git_clean)
assert "lint" in layers[1]
# Layer 3: format (tc.lint.format, depends on lint)
assert "format" in layers[2]
# Layer 4: typecheck (tc.typecheck, depends on format)
assert "typecheck" in layers[3]
# Layer 5: git_add_all (original TaskSpec, depends on typecheck)
assert "git_add_all" in layers[4]
# Layer 6: bumpversion (original TaskSpec, depends on git_add_all)
assert "bumpversion" in layers[5]
# Verify total layers
assert len(layers) == 6
def test_execution_order_only_references(self) -> None:
"""Should execute only references without original TaskSpecs."""
task1 = px.TaskSpec("task1", cmd=["echo", "1"])
task2 = px.TaskSpec("task2", cmd=["echo", "2"])
task3 = px.TaskSpec("task3", cmd=["echo", "3"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"cmd1": px.Graph.from_specs([task1]),
"cmd2": px.Graph.from_specs([task2]),
"cmd3": px.Graph.from_specs([task3]),
"all": px.Graph.from_specs(["cmd1", "cmd2", "cmd3"]),
},
)
# Check execution order through layers
layers = runner.graphs["all"].layers()
# Layer 1: task1 (cmd1)
assert "task1" in layers[0]
# Layer 2: task2 (cmd2, depends on task1)
assert "task2" in layers[1]
# Layer 3: task3 (cmd3, depends on task2)
assert "task3" in layers[2]
# Verify total layers
assert len(layers) == 3
def test_execution_order_only_original_tasks(self) -> None:
"""Should execute only original TaskSpecs without references."""
task1 = px.TaskSpec("task1", cmd=["echo", "1"])
task2 = px.TaskSpec("task2", cmd=["echo", "2"])
task3 = px.TaskSpec("task3", cmd=["echo", "3"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"all": px.Graph.from_specs([task1, task2, task3]),
},
)
# Check execution order through layers
layers = runner.graphs["all"].layers()
# All tasks should be in layer 1 (no dependencies)
assert "task1" in layers[0]
assert "task2" in layers[0]
assert "task3" in layers[0]
# Verify total layers
assert len(layers) == 1
def test_execution_order_single_reference(self) -> None:
"""Should execute single reference correctly."""
task1 = px.TaskSpec("task1", cmd=["echo", "1"])
task2 = px.TaskSpec("task2", cmd=["echo", "2"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"cmd1": px.Graph.from_specs([task1, task2]),
"all": px.Graph.from_specs(["cmd1"]),
},
)
# Check execution order through layers
layers = runner.graphs["all"].layers()
# Should have the same structure as cmd1
assert "task1" in layers[0]
assert "task2" in layers[0]
# Verify total layers
assert len(layers) == 1
def test_execution_order_deep_nesting(self) -> None:
"""Should execute deeply nested references correctly."""
task1 = px.TaskSpec("task1", cmd=["echo", "1"])
task2 = px.TaskSpec("task2", cmd=["echo", "2"])
task3 = px.TaskSpec("task3", cmd=["echo", "3"])
task4 = px.TaskSpec("task4", cmd=["echo", "4"])
task5 = px.TaskSpec("task5", cmd=["echo", "5"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"cmd1": px.Graph.from_specs([task1]),
"cmd2": px.Graph.from_specs(["cmd1", task2]),
"cmd3": px.Graph.from_specs(["cmd2", task3]),
"cmd4": px.Graph.from_specs(["cmd3", task4]),
"cmd5": px.Graph.from_specs(["cmd4", task5]),
},
)
# Check execution order through layers
layers = runner.graphs["cmd5"].layers()
# Should execute in order: task1 -> task2 -> task3 -> task4 -> task5
assert "task1" in layers[0]
assert "task2" in layers[1]
assert "task3" in layers[2]
assert "task4" in layers[3]
assert "task5" in layers[4]
# Verify total layers
assert len(layers) == 5
def test_execution_order_with_parallel_tasks_in_reference(self) -> None:
"""Should handle parallel tasks within referenced commands."""
task1 = px.TaskSpec("task1", cmd=["echo", "1"])
task2 = px.TaskSpec("task2", cmd=["echo", "2"])
task3 = px.TaskSpec("task3", cmd=["echo", "3"])
task4 = px.TaskSpec("task4", cmd=["echo", "4"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"cmd1": px.Graph.from_specs([task1, task2]), # Parallel tasks
"cmd2": px.Graph.from_specs([task3, task4]), # Parallel tasks
"all": px.Graph.from_specs(["cmd1", "cmd2"]),
},
)
# Check execution order through layers
layers = runner.graphs["all"].layers()
# Layer 1: task1 and task2 (cmd1, parallel)
assert "task1" in layers[0]
assert "task2" in layers[0]
# Layer 2: task3 and task4 (cmd2, depends on cmd1's last task)
# Note: Both task3 and task4 should depend on the last task of cmd1
assert "task3" in layers[1]
assert "task4" in layers[1]
# Verify total layers
assert len(layers) == 2
def test_execution_order_complex_mixed_scenario(self) -> None:
"""Should handle complex mixed scenario with references and TaskSpecs."""
# Create a complex scenario
clean = px.TaskSpec("clean", cmd=["echo", "clean"])
build1 = px.TaskSpec("build1", cmd=["echo", "build1"])
build2 = px.TaskSpec("build2", cmd=["echo", "build2"], depends_on=("build1",))
test1 = px.TaskSpec("test1", cmd=["echo", "test1"])
test2 = px.TaskSpec("test2", cmd=["echo", "test2"])
package = px.TaskSpec("package", cmd=["echo", "package"])
deploy = px.TaskSpec("deploy", cmd=["echo", "deploy"])
runner = px.CliRunner(
strategy="sequential",
graphs={
"clean": px.Graph.from_specs([clean]),
"build": px.Graph.from_specs([build1, build2]),
"test": px.Graph.from_specs([test1, test2]),
"release": px.Graph.from_specs(["clean", "build", "test", package, deploy]),
},
)
# Check execution order through layers
layers = runner.graphs["release"].layers()
# Layer 1: clean
assert "clean" in layers[0]
# Layer 2: build1 (depends on clean)
assert "build1" in layers[1]
# Layer 3: build2 (depends on build1)
assert "build2" in layers[2]
# Layer 4: test1 and test2 (depends on build2)
assert "test1" in layers[3]
assert "test2" in layers[3]
# Layer 5: package (depends on test1/test2)
assert "package" in layers[4]
# Layer 6: deploy (depends on package)
assert "deploy" in layers[5]
# Verify total layers
assert len(layers) == 6