Skip to content

Commit

Permalink
Add support for nested conditional YAML scheduling
Browse files Browse the repository at this point in the history
This allows to reference conditional schedules using the established
'{{foobar}}' syntax from within a conditional schedule as well.
  • Loading branch information
asdil12 committed Nov 11, 2020
1 parent 4cc5bed commit bf386bb
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 4 deletions.
1 change: 1 addition & 0 deletions declarative-schedule-doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ NOTE: Please, do not forget to wrap conditional schedule in quotes as `{` and `}

**NOTE:**
- [conditional_schedule](#conditional_schedule) does not allow at the moment to represent complex logic like combination of 'and' or 'or' and it does intend to do it due to potentially it would create the same problem that occurs with main.pm. Other kind of logic like a simple exclusion list could be feasible in the near future, for example "run for all except when this variable value is set to some specific value". Reusing of blocks needs to be re-thinked as well and what would be a readable syntax for this. At the moment if the scenario you intend to migrate has complex conditional logic it would require changes in your test modules.
- Nested conditional schedules (eg. referencing another conditional schedule from within a conditional schedule) are possible now.
- The only section that is mandatory is [schedule](#schedule). The rest of the sections in the YAML file can be skipped.

#### test_data
Expand Down
16 changes: 14 additions & 2 deletions lib/scheduler.pm
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,29 @@ sub parse_schedule {
my ($schedule) = shift;
my @scheduled;
for my $module (@{$schedule->{schedule}}) {
push(@scheduled, $module) && next unless ($module =~ s/\{\{(.*)\}\}/$1/);
push(@scheduled, parse_schedule_module($schedule, $module));

}
return @scheduled;
}

sub parse_schedule_module {
my ($schedule, $module) = @_;
my @scheduled;
if ($module =~ s/\{\{(.*)\}\}/$1/) {
# Module is scheduled conditionally. Need to be parsed. Get condition hash
my $condition = $schedule->{conditional_schedule}->{$module};
# Iterate over variables in the condition
foreach my $var (keys %{$condition}) {
next unless my $val = get_var($var);
# If value of the variable matched the conditions
# Iterate over the list of the modules to be loaded
push(@scheduled, $_) for (@{$condition->{$var}->{$val}});
push(@scheduled, parse_schedule_module($schedule, $_)) for (@{$condition->{$var}->{$val}});
}
}
else {
push(@scheduled, $module);
}
return @scheduled;
}

Expand Down
22 changes: 22 additions & 0 deletions t/02_yaml_schedule.t
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,26 @@ subtest 'parse_yaml_test_data_using_yaml_data_setting' => sub {
ok $testdata->{test_in_yaml_import_3} eq 'test_in_yaml_import_value_3', "Value in data file was overwritten by value in schedule file";
};

subtest 'parse_yaml_test_schedule_recursive_conditional' => sub {
use scheduler;
use testapi 'set_var';

my $schedule = $ypp->load_file(dirname(__FILE__) . '/data/test_schedule_recursive_conditional.yaml');
my @modules;
@modules = scheduler::parse_schedule($schedule);
ok $modules[0] eq 'bar/test0', "Basic scheduling";
ok $modules[1] eq 'bar/test3', "Basic scheduling";
set_var('VAR1', 'foo');
@modules = scheduler::parse_schedule($schedule);
ok $modules[0] eq 'bar/test0', "Basic scheduling";
ok $modules[1] eq 'foo/test1', "Conditional scheduling";
ok $modules[2] eq 'bar/test3', "Basic scheduling";
set_var('VAR2', 'foo');
@modules = scheduler::parse_schedule($schedule);
ok $modules[0] eq 'bar/test0', "Basic scheduling";
ok $modules[1] eq 'foo/test1', "Conditional scheduling";
ok $modules[2] eq 'foo/test2', "Recursive conditional scheduling";
ok $modules[3] eq 'bar/test3', "Basic scheduling";
};

done_testing;
14 changes: 14 additions & 0 deletions t/data/test_schedule_recursive_conditional.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
conditional_schedule:
cond2:
VAR2:
'foo':
- foo/test2
cond1:
VAR1:
'foo':
- foo/test1
- '{{cond2}}'
schedule:
- bar/test0
- '{{cond1}}'
- bar/test3
15 changes: 13 additions & 2 deletions tools/detect_nonexistent_modules_in_yaml_schedule
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,28 @@ sub parse_modules_in_schedule {
my $schedule = $ypp->load_file($schedule_file_path);
my @scheduled;
for my $module (@{$schedule->{schedule}}) {
push(@scheduled, $module) && next unless ($module =~ s/\{\{(.*)\}\}/$1/);
push(@scheduled, parse_schedule_module($schedule, $module));
}
return @scheduled;
}

sub parse_schedule_module {
my ($schedule, $module) = @_;
my @scheduled;
if ($module =~ s/\{\{(.*)\}\}/$1/) {
# Module is scheduled conditionally. Need to be parsed. Get condition hash
my $condition = $schedule->{conditional_schedule}->{$module};
# Iterate over variables in the condition
foreach my $var (keys %{$condition}) {
foreach my $val (keys %{$condition->{$var}}) {
# Iterate over the list of the modules to be loaded
push(@scheduled, $_) for (@{$condition->{$var}->{$val}});
push(@scheduled, parse_schedule_module($schedule, $_)) for (@{$condition->{$var}->{$val}});
}
}
}
else {
push(@scheduled, $module);
}
return @scheduled;
}

Expand Down

0 comments on commit bf386bb

Please sign in to comment.