Skip to content

Commit

Permalink
Merge pull request #15 from uselagoon/feature/conditional_steps
Browse files Browse the repository at this point in the history
Feature/conditional steps
  • Loading branch information
bomoko authored Aug 29, 2023
2 parents fd9e3b1 + 7912252 commit 601c2fa
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 63 deletions.
22 changes: 20 additions & 2 deletions src/Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Migrator;

use Migrator\Step\DynamicEnvironmentTrait;
use Migrator\Step\StepParent;

class Runner
{
use LoggerTrait;
Expand Down Expand Up @@ -40,8 +43,23 @@ public function __get($name)
public function run()
{
foreach ($this->steps as $step) {
//determine if this is a step or an assertion
if (!empty($step['assertTrue']) || !empty($step['assertFalse'])) {

//determine if this is a step or an assertion or conditional
if($step['type'] == "conditional") {
// we determine if the condition is "true" - if so, we run the steps recursively
if(!isset($step['condition'])) {
throw new \Exception(sprintf("Failed on step '%s' - no condition attached", $step['name']));
}

$condition = DynamicEnvironmentTrait::renderText($step['condition']);

if($condition == true) {
$args = $this->args;
$args->steps = $step['steps'];
$runner = new Runner($args);
$runner->run();
}
} else if (!empty($step['assertTrue']) || !empty($step['assertFalse'])) {
$this->runAssertion($step);
} else {
$this->runStep($step);
Expand Down
62 changes: 62 additions & 0 deletions src/Step/DynamicEnvironmentTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace Migrator\Step;

use function WyriHaximus\Twig\render;

trait DynamicEnvironmentTrait {

static $dynamicEnvironment = [];

public static function fillDynamicEnvironmentFromEnv() {
$envVars = getenv();
foreach ($envVars as $key => $val) {
if($key == "JSON_PAYLOAD") {
self::fillDynamicEnvironmentFromJSONPayload($val);
} else {
self::setVariable(sprintf("%s", $key), $val);
}

}
}

public static function fillDynamicEnvironmentFromJSONPayload($payload) {

$decodedJson = base64_decode($payload);
if(!$decodedJson) {
throw new \Exception("Found JSON_PAYLOAD but could not decode it");
}

$vars = json_decode($decodedJson, true);

if(json_last_error() > 0) {
throw new \Exception(sprintf("Could not decode JSONPAYLOAD: %s ", json_last_error_msg()));
}

foreach ($vars as $key => $val) {
self::setVariable($key, $val);
}
}

public static function setVariable($name, $value) {
self::$dynamicEnvironment[$name] = $value;
}

public static function getVariable($name) {
if(!key_exists($name, self::$dynamicEnvironment)) {
throw new \Exception("Unable to find variable {$name} in dynamic environment - have you previously set it?");
}
return self::$dynamicEnvironment[$name];
}

public static function getAllVariables() {
return self::$dynamicEnvironment;
}

public static function renderText($template, $extraVars = [])
{
$subs = array_merge(self::getAllVariables(), $extraVars);
return render($template, $subs);
}

}
60 changes: 3 additions & 57 deletions src/Step/StepParent.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,62 +12,14 @@

abstract class StepParent implements StepInterface
{
use LoggerTrait;
use LoggerTrait, DynamicEnvironmentTrait;
protected $cluster;
protected $namespace;
protected $utilityBelt;
protected $token;
protected $args;
protected $commandName;

static $dynamicEnvironment = [];


public static function fillDynamicEnvironmentFromEnv() {
$envVars = getenv();
foreach ($envVars as $key => $val) {
if($key == "JSON_PAYLOAD") {
self::fillDynamicEnvironmentFromJSONPayload($val);
} else {
self::setVariable(sprintf("%s", $key), $val);
}

}
}

public static function fillDynamicEnvironmentFromJSONPayload($payload) {

$decodedJson = base64_decode($payload);
if(!$decodedJson) {
throw new \Exception("Found JSON_PAYLOAD but could not decode it");
}

$vars = json_decode($decodedJson, true);

if(json_last_error() > 0) {
throw new \Exception(sprintf("Could not decode JSONPAYLOAD: %s ", json_last_error_msg()));
}

foreach ($vars as $key => $val) {
self::setVariable($key, $val);
}
}

public static function setVariable($name, $value) {
self::$dynamicEnvironment[$name] = $value;
}

public static function getVariable($name) {
if(!key_exists($name, self::$dynamicEnvironment)) {
throw new \Exception("Unable to find variable {$name} in dynamic environment - have you previously set it?");
}
return self::$dynamicEnvironment[$name];
}

public static function getAllVariables() {
return self::$dynamicEnvironment;
}

public function __construct(LagoonUtilityBeltInterface $utilityBelt, RunnerArgs $args)
{
$this->cluster = $args->cluster;
Expand Down Expand Up @@ -106,19 +58,13 @@ public function run(array $args) {
*/
public function doTextSubstitutions($string)
{
$substitutions = [
$extraSubs = [
'project' => $this->args->project,
'environment' => $this->args->environment,
'namespace' => $this->args->namespace,
];

//Here we reach into the dynamic environment to grab any other arbitrarily defined vars
foreach (self::getAllVariables() as $key => $value) {
$substitutions[$key] = $value;
}


return render($string, $substitutions);
return self::renderText($string, $extraSubs);
}

// We use dynamic dispatch to allow us to do some logging and
Expand Down
22 changes: 20 additions & 2 deletions src/Step/Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,28 @@

class Test extends StepParent {

public static $callbacks = [];

public static function setCallback(callable $cb)
{
self::$callbacks[] = $cb;
}

public static function clearCallbacks()
{
self::$callbacks = [];
}

public function runImplementation(array $args)
{
//check we have all the args we need
//TODO: can be used to test things - will be removed
// check we have all the args we need
// we just run through all the registered callbacks and call them with the args
// This allows tests to attach their functions
foreach (self::$callbacks as $callback) {
if(is_callable($callback)) {
$callback($args);
}
}
}

}
4 changes: 2 additions & 2 deletions tests/DeployTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function testStandardTextualSubstitutionsInArgs() {

// Here we replace LAGOON_BACKUPS_DISABLED with whatever is
// placed into the dynamic environment
$buildVars = ['LAGOON_BACKUPS_DISABLED', '{{ LAGOON_BACKUPS_DISABLED }}'];
$buildVars = [["name" => 'LAGOON_BACKUPS_DISABLED', "value"=>'{{ LAGOON_BACKUPS_DISABLED }}']];

$args = [
'project' => 'testproject',
Expand All @@ -58,7 +58,7 @@ public function testStandardTextualSubstitutionsInArgs() {
];

// Once the textual subs for $buildVars is done, we expect the following...
$buildWithSubs = ['LAGOON_BACKUPS_DISABLED', 'false'];
$buildWithSubs = [["name" => 'LAGOON_BACKUPS_DISABLED', "value"=>'false']];

$lub->expects($this->once())
->method("deployEnvironment")
Expand Down
137 changes: 137 additions & 0 deletions tests/RunnerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

use Migrator\Runner;
use PHPUnit\Framework\TestCase;

class RunnerTest extends TestCase
{

protected function getStepsFromFile($filename)
{
return \Symfony\Component\Yaml\Yaml::parse(
file_get_contents($filename)
);
}

/**
* This test will simply check that the runner works generally
*
* @return void
*/
function testBasicCase()
{
//just testing the test case callback
$testRan = false;
$cb = function ($args) use (&$testRan) {
$testRan = true;
};
\Migrator\Step\Test::setCallback($cb);

$steps = $this->getStepsFromFile(
__DIR__ . "/assets/RunnerTestBasicCase.yaml"
);
$args = new \Migrator\RunnerArgs();
$args->steps = $steps['steps'];
$runner = new \Migrator\Runner($args);
$runner->run();
$this->assertTrue($testRan);
\Migrator\Step\Test::clearCallbacks();
}

/**
* This drives/tests the conditional system - basic conditional
* Further tests will work on textual substitutions etc.
*
* @return void
*/
function testConditionalRun()
{
//just testing the test case callback
$conditionalStepRan = false;
$cb = function ($args) use (&$conditionalStepRan) {
if(!empty($args['testid']) && $args['testid'] == 1)
{
$conditionalStepRan = true;
}
};
\Migrator\Step\Test::setCallback($cb);

$steps = $this->getStepsFromFile(
__DIR__ . "/assets/RunnerTestConditionalRun.yaml"
);
$args = new \Migrator\RunnerArgs();
$args->steps = $steps['steps'];
$runner = new \Migrator\Runner($args);
$runner->run();
$this->assertTrue($conditionalStepRan);
\Migrator\Step\Test::clearCallbacks();
}

/**
* This drives/tests the conditional system - basic conditional
* Further tests will work on textual substitutions etc.
*
* @return void
*/
function testConditionalDidntRun()
{
//just testing the test case callback
$conditionalStepRan = false;
$cb = function ($args) use (&$conditionalStepRan) {
if(!empty($args['testid']) && $args['testid'] == 1)
{
$conditionalStepRan = true;
}
};
\Migrator\Step\Test::setCallback($cb);

$steps = $this->getStepsFromFile(
__DIR__ . "/assets/RunnerTestConditionalDidntRun.yaml"
);
$args = new \Migrator\RunnerArgs();
$args->steps = $steps['steps'];
$runner = new \Migrator\Runner($args);
$runner->run();
$this->assertFalse($conditionalStepRan);
\Migrator\Step\Test::clearCallbacks();
}

/**
* This drives/tests the conditional system - basic conditional
* Further tests will work on textual substitutions etc.
*
* @return void
*/
function testConditionalWithTwigConditions()
{
//just testing the test case callback
$conditionalStepShouldHaveRun = false;
\Migrator\Step\DynamicEnvironmentTrait::setVariable('RUN_THIS', "true");
\Migrator\Step\DynamicEnvironmentTrait::setVariable('DONT_RUN_THAT', "true");
$conditionalStepShouldNotHaveRun = true;
$cb = function ($args) use (&$conditionalStepShouldHaveRun, &$conditionalStepShouldNotHaveRun) {
if(!empty($args['testid']) && $args['testid'] == 1)
{
$conditionalStepShouldHaveRun = true;
}
if(!empty($args['testid']) && $args['testid'] == 2)
{
$conditionalStepShouldNotHaveRun = false;
}
};
\Migrator\Step\Test::setCallback($cb);

$steps = $this->getStepsFromFile(
__DIR__ . "/assets/RunnerTestConditionalTwig.yaml"
);
$args = new \Migrator\RunnerArgs();
$args->steps = $steps['steps'];
$runner = new \Migrator\Runner($args);
$runner->run();
$this->assertTrue($conditionalStepShouldHaveRun);
$this->assertTrue($conditionalStepShouldNotHaveRun);

\Migrator\Step\Test::clearCallbacks();
}

}
3 changes: 3 additions & 0 deletions tests/assets/RunnerTestBasicCase.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
steps:
- name: basic run test
type: test
10 changes: 10 additions & 0 deletions tests/assets/RunnerTestConditionalDidntRun.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
steps:
- name: basic run test
type: test
- name: conditional will always run
type: conditional
condition: false
steps:
- name: conditional first level
type: test
testid: 1
Loading

0 comments on commit 601c2fa

Please sign in to comment.