Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dependencies = [
# SymbolTable.expr_host_rules, and `let` on StepTemplate/StepScript. 0.11.0 has
# only StepTemplate.let, StepScript.let and SymbolTable.expr_types, so this
# package fails at import against it.
"openjd-model >= 0.11.1,< 0.12",
"openjd-model >= 0.11.2,< 0.12",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The floor was bumped to 0.11.2, but the comment above still explains only why 0.11.1 was the floor ("0.11.1 is the floor because…"). Since run_task now forwards step_name to the Rust binding, 0.11.2 is presumably required because it is the first release whose Session.run_task accepts step_name / surfaces WrappedStep.Name. Worth adding a line documenting that so the rationale for the new floor is captured (otherwise a future reader could mistakenly relax it back to 0.11.1, which would break run_task(step_name=…) at runtime).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK since we're doing minor bumps.

"pywin32 >= 307; platform_system == 'Windows'",
"psutil >= 5.9,< 7.3; platform_system == 'Windows'",
]
Expand Down
5 changes: 5 additions & 0 deletions src/openjd/sessions/_v1/_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ def run_task(
os_env_vars: Optional[dict[str, str]] = None,
log_task_banner: bool = True,
resolved_symtab: Optional[SerializedSymbolTable] = None,
step_name: Optional[str] = None,
) -> None:
# ``resolved_symtab`` is the step-scope symbol table generated
# by ``create_job`` (available as ``Step.resolved_symtab``).
Expand All @@ -310,6 +311,9 @@ def run_task(
# bindings and no expression interpolation that depends on
# step-scope state.
#
# ``step_name`` is surfaced as ``WrappedStep.Name`` to a wrapping
# environment's ``onWrapTaskRun`` hook (RFC 0008).
#
# ``log_task_banner`` is accepted for API compatibility but
# currently has no effect — the Rust runner always emits the
# task banner. TODO: plumb through if/when the Rust API
Expand All @@ -319,6 +323,7 @@ def run_task(
task_parameter_values=task_parameter_values,
resolved_symtab=resolved_symtab,
os_env_vars=os_env_vars,
step_name=step_name,
)
self._fire_initial_running_callback()
self._poll_for_completion()
Expand Down
107 changes: 107 additions & 0 deletions test/openjd/sessions_v1/test_wrap_task_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

"""Tests that the _v1 Session.run_task accepts and forwards step_name
to the Rust binding without error (RFC 0008).

The full wrap-action integration (``{{WrappedStep.Name}}`` resolution inside an
``onWrapTaskRun`` hook) is validated by the worker-agent's differential runtime
test. This test verifies the _v1 Python wrapper plumbs the kwarg through.
"""

from __future__ import annotations

import time
import uuid
from pathlib import Path

import pytest

from openjd.model._v1 import create_job, decode_job_template
from openjd.sessions._v1 import Session, SessionState, ActionState

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

_SIMPLE_TEMPLATE = {
"specificationVersion": "jobtemplate-2023-09",
"name": "StepNameTest",
"steps": [
{
"name": "MyStep",
"script": {
"actions": {
"onRun": {"command": "echo", "args": ["hello-from-task"]},
}
},
}
],
}


def _run_until_ready(session: Session, timeout_s: float = 10.0) -> None:
deadline = time.time() + timeout_s
while session.state == SessionState.RUNNING and time.time() < deadline:
time.sleep(0.05)


# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------


class TestV1RunTaskStepName:
"""Verify that _v1 Session.run_task forwards step_name to the Rust binding."""

def test_run_task_accepts_step_name(
self, tmp_path: Path, caplog: pytest.LogCaptureFixture
) -> None:
"""run_task(step_name=...) succeeds and the task completes normally."""
job_template = decode_job_template(template=_SIMPLE_TEMPLATE)
job = create_job(job_template=job_template, job_parameter_values={})
step = job.steps[0]

with Session(
session_id=uuid.uuid4().hex,
job_parameter_values={},
session_root_directory=tmp_path,
) as session:
session.run_task(
step_script=step.script,
task_parameter_values={},
resolved_symtab=step.resolved_symtab,
step_name="MyStep",
)
_run_until_ready(session)

assert session.state == SessionState.READY
assert session.action_status is not None
assert session.action_status.state == ActionState.SUCCESS
assert session.action_status.exit_code == 0

messages = "\n".join(caplog.messages)
assert "hello-from-task" in messages

def test_run_task_step_name_none_also_works(self, tmp_path: Path) -> None:
"""step_name=None (the default) still works."""
job_template = decode_job_template(template=_SIMPLE_TEMPLATE)
job = create_job(job_template=job_template, job_parameter_values={})
step = job.steps[0]

with Session(
session_id=uuid.uuid4().hex,
job_parameter_values={},
session_root_directory=tmp_path,
) as session:
session.run_task(
step_script=step.script,
task_parameter_values={},
resolved_symtab=step.resolved_symtab,
# step_name defaults to None
)
_run_until_ready(session)

assert session.state == SessionState.READY
assert session.action_status is not None
assert session.action_status.state == ActionState.SUCCESS
assert session.action_status.exit_code == 0
Loading