-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add validation for duplicate template and node names (#1054)
**Pull Request Checklist** - [ ] Fixes #<!--issue number goes here--> - [x] Tests added - [x] Documentation/examples added - [x] [Good commit messages](https://cbea.ms/git-commit/) and/or PR title **Description of PR** Currently, hera lacks validation for duplicate template names, causing templates with duplicate names to be missing when rendering to yaml. Hera also lacks validation for duplicate node names, which results in rendered yaml that is invalid when submitted to argo-workflows. This PR adds validation for both situations, preventing the user from rendering incorrect or invalid yaml when Workflows contain multiple templates or nodes with the same name by raising a TemplateNameConflict or NodeNameConflict, respectively. Note that the order of operations has been adjusted in `_HeraContext.add_sub_node`. This change was required to continue to support workflows with recursive references. --------- Signed-off-by: crflynn <flynn@simplebet.io> Signed-off-by: Elliot Gunton <elliotgunton@gmail.com> Co-authored-by: Elliot Gunton <elliotgunton@gmail.com>
- Loading branch information
1 parent
08038f0
commit fe4d5c9
Showing
7 changed files
with
189 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import pytest | ||
|
||
from hera.workflows import DAG, Steps, WorkflowTemplate, script | ||
from hera.workflows.exceptions import NodeNameConflict, TemplateNameConflict | ||
|
||
|
||
class TestContextNameConflicts: | ||
"""These tests ensure that template and node name conflicts raise Exceptions. | ||
This should validate that no two templates have the same name, | ||
and that no two Task/Step nodes have the same name. | ||
""" | ||
|
||
def test_conflict_on_templates_with_same_name(self): | ||
"""Multiple templates can't have the same name.""" | ||
name = "name-of-dag-and-script" | ||
|
||
@script(name=name) | ||
def example(): | ||
print("hello") | ||
|
||
with pytest.raises(TemplateNameConflict): | ||
with WorkflowTemplate(name="my-workflow", entrypoint=name), DAG(name=name): | ||
example() | ||
|
||
with pytest.raises(TemplateNameConflict): | ||
with WorkflowTemplate( | ||
name="my-workflow", | ||
entrypoint=name, | ||
), Steps(name=name): | ||
example() | ||
|
||
def test_no_conflict_on_tasks_with_different_names_using_same_template(self): | ||
"""Task nodes can have different names for the same script template.""" | ||
dag_name = "dag-name" | ||
name_1 = "task-1" | ||
name_2 = "task-2" | ||
|
||
@script() | ||
def example(): | ||
print("hello") | ||
|
||
with WorkflowTemplate( | ||
name="my-workflow", | ||
entrypoint=dag_name, | ||
), DAG(name=dag_name): | ||
example(name=name_1) | ||
example(name=name_2) | ||
|
||
def test_no_conflict_on_dag_and_task_with_same_name(self): | ||
"""Dag and task node can have the same name.""" | ||
name = "name-of-dag-and-task" | ||
|
||
@script() | ||
def example(): | ||
print("hello") | ||
|
||
with WorkflowTemplate( | ||
name="my-workflow", | ||
entrypoint=name, | ||
), DAG(name=name): | ||
example(name=name) # task name same as dag template | ||
|
||
with WorkflowTemplate( | ||
name="my-workflow", | ||
entrypoint=name, | ||
), Steps(name=name): | ||
example(name=name) # step name same as steps template | ||
|
||
def test_conflict_on_multiple_tasks_with_same_name(self): | ||
"""Dags cannot have two task nodes with the same name.""" | ||
name = "name-of-tasks" | ||
|
||
@script() | ||
def hello(): | ||
print("hello") | ||
|
||
@script() | ||
def world(): | ||
print("world") | ||
|
||
with pytest.raises(NodeNameConflict): | ||
with WorkflowTemplate(name="my-workflow", entrypoint="dag"), DAG(name="dag"): | ||
hello(name=name) | ||
world(name=name) | ||
|
||
with pytest.raises(NodeNameConflict): | ||
with WorkflowTemplate(name="my-workflow", entrypoint="steps"), Steps(name="steps"): | ||
hello(name=name) | ||
world(name=name) | ||
|
||
with pytest.raises(NodeNameConflict): | ||
with WorkflowTemplate( | ||
name="my-workflow", | ||
entrypoint="steps", | ||
), Steps(name="steps") as s: | ||
hello(name=name) | ||
with s.parallel(): | ||
world(name=name) | ||
|
||
with pytest.raises(NodeNameConflict): | ||
with WorkflowTemplate( | ||
name="my-workflow", | ||
entrypoint="steps", | ||
), Steps(name="steps") as s: | ||
with s.parallel(): | ||
hello(name=name) | ||
world(name=name) | ||
|
||
with pytest.raises(NodeNameConflict): | ||
with WorkflowTemplate( | ||
name="my-workflow", | ||
entrypoint="steps", | ||
), Steps(name="steps") as s: | ||
with s.parallel(): | ||
hello(name=name) | ||
with s.parallel(): | ||
world(name=name) |