Skip to content

Commit 573beec

Browse files
committed
Add support for issue-config iterate
1 parent 4e91269 commit 573beec

File tree

4 files changed

+146
-16
lines changed

4 files changed

+146
-16
lines changed

README.md

+59
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,40 @@ issues:
113113

114114
Individual settings are described below.
115115

116+
#### environment
117+
118+
Defines environment varibles that will be set when sheduling a recipe.
119+
This definition takes priority over environment definition in a recipe so better
120+
avoid defining identical variable in both places.
121+
Environment definition is not inherited by child Jira issues.
122+
123+
Example:
124+
```
125+
- summary: "regression testing"
126+
descriptin: "task descryption"
127+
type: task
128+
environment:
129+
MYVAR: myvalue
130+
...
131+
```
132+
133+
#### context
134+
135+
Defines custom `tmt` context setting that will be set when scheduling a recipe.
136+
This definition takes priority over context definition in a recipe so better
137+
avoid defining identical context dimension in both places.
138+
Context definition is not inherited by child Jira issues.
139+
140+
Example:
141+
```
142+
- summary: "regression testing"
143+
descriptin: "task descryption"
144+
type: task
145+
context:
146+
swtpm: yes
147+
...
148+
```
149+
116150
#### include
117151

118152
Allows user to import snippet of a file from a different URL location or a file.
@@ -121,6 +155,31 @@ has lower priority and the whole section is replaced completely.
121155
The only exceptions are are `issues` and `defaults` which are merged.
122156
To unset a value defined in an included file one can set the value to `null`.
123157

158+
159+
#### iterate
160+
161+
Enables a user to do multiple copies of the respective action that differ in some parameters.
162+
These parameters will be automatically added to `environment` variable definition used for a recipe.
163+
Multiple variables can be defined for a single iteration, those will eventually override identical
164+
variables defined in `environment` attribute.
165+
166+
Example:
167+
In this example two subtasks will be created with variables `FOO` and `DESCRIPTION` being set accordingly.
168+
```
169+
- summary: "regression testing - FOO={{ ENVIRONMENT.FOO }}"
170+
description: "{{ ENVIRONMENT.DESCRIPTION }}"
171+
type: subtask
172+
environment:
173+
MYVAR: thisismyvar
174+
DESCRIPTION: default description
175+
iterate:
176+
# this is the first iteration
177+
- FOO: bar
178+
DESCRIPTION: non-default description
179+
# this is the second iteration
180+
- FOO: baz
181+
```
182+
124183
#### project and group
125184

126185
Defines Jira project to be used by NEWA and optionally also a user group for access restrictions.

component-config.yaml.sample

+11-2
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,19 @@ issues:
5353
parent_id: errata_task
5454
on_respin: close
5555

56-
- summary: "regression testing"
57-
description: "Run automated tests"
56+
- summary: "regression testing - FOO={{ ENVIRONMENT.FOO }}"
57+
description: "{{ ENVIRONMENT.ISSUE_DESC }}"
5858
type: subtask
5959
parent_id: errata_task
6060
on_respin: close
6161
auto_transition: True
6262
job_recipe: https://raw.githubusercontent.com/RedHatQE/newa/ks_recipe_job/component-recipe.yaml.sample
63+
iterate:
64+
- FOO: bar
65+
ISSUE_DESC: non-default description
66+
- FOO: baz
67+
environment:
68+
MYVAR: thisismyvar
69+
ISSUE_DESC: default description
70+
context:
71+
universe: parallel

newa/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,8 @@ class Recipe(Cloneable, Serializable):
742742
""" A job recipe """
743743

744744
url: str
745+
context: Optional[RecipeContext] = None
746+
environment: Optional[RecipeEnvironment] = None
745747

746748

747749
# A tmt context for a recipe, dimension -> value mapping.
@@ -1292,6 +1294,9 @@ class IssueAction(Serializable): # type: ignore[no-untyped-def]
12921294
when: Optional[str] = None
12931295
newa_id: Optional[str] = None
12941296
fields: Optional[dict[str, str | float | list[str]]] = None
1297+
iterate: Optional[list[RecipeEnvironment]] = None
1298+
context: Optional[RecipeContext] = None
1299+
environment: Optional[RecipeEnvironment] = None
12951300

12961301
# function to handle issue-config file defaults
12971302

newa/cli.py

+71-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import copy
12
import datetime
23
import io
34
import logging
@@ -591,12 +592,44 @@ def _jira_fake_id_generator() -> Generator[str, int, None]:
591592

592593
ctx.logger.info(f"Processing {action.id}")
593594

595+
# check if there are iteration is defined
596+
if action.iterate:
597+
# for each value prepare a separate action
598+
for i, iter_vars in enumerate(action.iterate):
599+
ctx.logger.debug(f"Processing iteration: {iter_vars}")
600+
new_action = copy.deepcopy(action)
601+
new_action.iterate = None
602+
if not new_action.environment:
603+
new_action.environment = copy.deepcopy(iter_vars)
604+
else:
605+
new_action.environment = copy.deepcopy(
606+
{**new_action.environment, **iter_vars})
607+
new_action.id = f"{new_action.id}.iter{i + 1}"
608+
ctx.logger.debug(f"Created issue config action: {new_action}")
609+
issue_actions.insert(i, new_action)
610+
ctx.logger.info(f"Created {i} iterations of action {action.id}")
611+
# now all iterations for a given action, let's process them one by one
612+
continue
613+
614+
# update action.environment and action.context for jinja template rendering
615+
if action.context:
616+
action.context = copy.deepcopy(
617+
{**ctx.cli_context, **action.context})
618+
else:
619+
action.context = copy.deepcopy(ctx.cli_context)
620+
if action.environment:
621+
action.environment = copy.deepcopy(
622+
{**ctx.cli_environment, **action.environment})
623+
else:
624+
action.environment = copy.deepcopy(ctx.cli_environment)
625+
594626
if action.when and not eval_test(action.when,
595627
JOB=artifact_job,
596628
EVENT=artifact_job.event,
597629
ERRATUM=artifact_job.erratum,
598630
COMPOSE=artifact_job.compose,
599-
ENVIRONMENT=ctx.cli_environment):
631+
CONTEXT=action.context,
632+
ENVIRONMENT=action.environment):
600633
ctx.logger.info(f"Skipped, issue action is irrelevant ({action.when})")
601634
continue
602635

@@ -609,12 +642,14 @@ def _jira_fake_id_generator() -> Generator[str, int, None]:
609642
action.summary,
610643
ERRATUM=artifact_job.erratum,
611644
COMPOSE=artifact_job.compose,
612-
ENVIRONMENT=ctx.cli_environment)
645+
CONTEXT=action.context,
646+
ENVIRONMENT=action.environment)
613647
rendered_description = render_template(
614648
action.description,
615649
ERRATUM=artifact_job.erratum,
616650
COMPOSE=artifact_job.compose,
617-
ENVIRONMENT=ctx.cli_environment)
651+
CONTEXT=action.context,
652+
ENVIRONMENT=action.environment)
618653
if assignee:
619654
rendered_assignee = assignee
620655
elif unassigned:
@@ -624,15 +659,17 @@ def _jira_fake_id_generator() -> Generator[str, int, None]:
624659
action.assignee,
625660
ERRATUM=artifact_job.erratum,
626661
COMPOSE=artifact_job.compose,
627-
ENVIRONMENT=ctx.cli_environment)
662+
CONTEXT=action.context,
663+
ENVIRONMENT=action.environment)
628664
else:
629665
rendered_assignee = None
630666
if action.newa_id:
631667
action.newa_id = render_template(
632668
action.newa_id,
633669
ERRATUM=artifact_job.erratum,
634670
COMPOSE=artifact_job.compose,
635-
ENVIRONMENT=ctx.cli_environment)
671+
CONTEXT=action.context,
672+
ENVIRONMENT=action.environment)
636673

637674
# Detect that action has parent available (if applicable), if we went trough the
638675
# actions already and parent was not found, we abort.
@@ -803,14 +840,19 @@ def _jira_fake_id_generator() -> Generator[str, int, None]:
803840
action.job_recipe,
804841
ERRATUM=artifact_job.erratum,
805842
COMPOSE=artifact_job.compose,
806-
ENVIRONMENT=ctx.cli_environment)
843+
CONTEXT=action.context,
844+
ENVIRONMENT=action.environment)
807845
if action.erratum_comment_triggers:
808846
new_issue.erratum_comment_triggers = action.erratum_comment_triggers
809-
jira_job = JiraJob(event=artifact_job.event,
810-
erratum=artifact_job.erratum,
811-
compose=artifact_job.compose,
812-
jira=new_issue,
813-
recipe=Recipe(url=recipe_url))
847+
jira_job = JiraJob(
848+
event=artifact_job.event,
849+
erratum=artifact_job.erratum,
850+
compose=artifact_job.compose,
851+
jira=new_issue,
852+
recipe=Recipe(
853+
url=recipe_url,
854+
context=action.context,
855+
environment=action.environment))
814856
ctx.save_jira_job('jira-', jira_job)
815857

816858
# Processing old issues - we only expect old issues that are to be closed (if any).
@@ -843,7 +885,10 @@ def _jira_fake_id_generator() -> Generator[str, int, None]:
843885
erratum=artifact_job.erratum,
844886
compose=artifact_job.compose,
845887
jira=new_issue,
846-
recipe=Recipe(url=job_recipe))
888+
recipe=Recipe(
889+
url=job_recipe,
890+
context=ctx.cli_context,
891+
environment=ctx.cli_environment))
847892
ctx.save_jira_job('jira-', jira_job)
848893

849894

@@ -880,9 +925,21 @@ def cmd_schedule(ctx: CLIContext, arch: list[str], fixtures: list[str]) -> None:
880925
else:
881926
architectures = jira_job.erratum.archs if (
882927
jira_job.erratum and jira_job.erratum.archs) else Arch.architectures()
928+
929+
# prepare initial config copying it from jira_job,recipe but overriding with cli input
930+
if jira_job.recipe.context:
931+
initial_context = copy.deepcopy(
932+
{**ctx.cli_context, **jira_job.recipe.context})
933+
else:
934+
initial_context = copy.deepcopy(ctx.cli_context)
935+
if jira_job.recipe.environment:
936+
initial_environment = copy.deepcopy(
937+
{**ctx.cli_environment, **jira_job.recipe.environment})
938+
else:
939+
initial_environment = copy.deepcopy(ctx.cli_environment)
883940
initial_config = RawRecipeConfigDimension(compose=compose,
884-
environment=ctx.cli_environment,
885-
context=ctx.cli_context)
941+
environment=initial_environment,
942+
context=initial_context)
886943
ctx.logger.debug(f'Initial config: {initial_config})')
887944
if fixtures:
888945
for fixture in fixtures:

0 commit comments

Comments
 (0)