Source of file PipelineStep.php
Size: 7,460 Bytes - Last Modified: 2021-12-23T10:29:15+00:00
/var/www/docs.ssmods.com/process/src/code/model/steps/PipelineStep.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 | <?php /** * Represents a single step in a pipeline * * Caveat inheritors: apparently PipelineStep must call their respective Pipeline's markFailed() function upon failure. * * <code> * MyStep: * Class: ClassOfStep * NiceName: "Name of this step to display on frontend" * NiceDone: "Name of this step to display on frontend once finished" * </code> * * @method Pipeline Pipeline() * * @package deploynaut * @subpackage pipeline */ class PipelineStep extends DataObject implements PipelineData { /** * @var array * - Order: The order in which this step is to be executed within the {@link Pipeline}. * Links to the 'Pipeline' has_one below. * - Status: The status if this particular step in the Pipeline. You can always query $this->Pipeline()->Status to * see the overall status of the pipeline itself. */ private static $db = array( 'Name' => 'Varchar(255)', 'Order' => 'Int', 'Status' => 'Enum("Queued,Started,Finished,Failed,Aborted,n/a", "n/a")', 'Config' => 'Text' // serialized array of configuration for this step ); private static $has_one = array( 'Pipeline' => 'Pipeline' ); /** * @var string Ensure we use the 'Order' int as the sort order. This means that all code that references * {@link Pipeline::PipelineSteps()} will always get the steps in the same order. */ private static $default_sort = 'Order'; private static $summary_fields = array( 'Name', 'Status', 'LastEdited' ); /** * Cached of config merged with defaults * * @var array */ protected $mergedConfig; /** * Title of this step * * @return string */ public function getTitle() { return $this->Name ?: get_class($this); } public function getTreeTitle() { return $this->Title . ' (Status: ' . $this->Status . ')'; } public function getNiceName() { $niceName = $this->getConfigSetting('NiceName') ?: ucwords(trim(strtolower(preg_replace('/_?([A-Z])/', ' $1', $this->getTitle())))); if($this->isFinished()) { $niceName = $this->getConfigSetting('NiceDone') ?: $niceName; } return $niceName; } /** * Unserializes a snippet of configuration that was saved at the time this step * was created at {@link Pipeline::start()} so that this step can use that configuration * to determine what it needs to do. e.g for SmokeTestPipelineStep this might contain * a list of URLs that need to be checked and which status codes to check for. * * @return array */ public function getConfigData() { if(!$this->Config) return array(); // Merge with defaults if(!$this->mergedConfig) { $this->mergedConfig = unserialize($this->Config); if($default = self::config()->default_config) { Config::merge_array_low_into_high($this->mergedConfig, $default); } } return $this->mergedConfig; } public function setConfig($data) { $this->mergedConfig = null; return parent::setField('Config', $data); } /** * Describe what the step is currently doing. * * @return string */ public function getRunningDescription() { return ''; } /** * Retrieve the value of a specific config setting * * @param string $setting Settings * @param string $setting,... Sub-settings * @return mixed Value of setting, or null if not set */ public function getConfigSetting($setting) { $source = $this->getConfigData(); foreach(func_get_args() as $setting) { if(empty($source[$setting])) return null; $source = $source[$setting]; } return $source; } public function finish() { $this->Status = 'Finished'; $this->log('Step finished successfully!'); $this->write(); } /** * Fail this pipeline step * * @param bool $notify Set to false to disable notifications for this failure */ public function markFailed($notify = true) { $this->Status = 'Failed'; $this->log('Marking pipeline step as failed. See earlier log messages to determine cause.'); $this->write(); $this->Pipeline()->markFailed($notify); } /** * Determine if this step is in progress (Started state). * * @return boolean */ public function isQueued() { return $this->Status === 'Queued'; } /** * Determine if this step is in progress (Started state). * * @return boolean */ public function isRunning() { return $this->Status === 'Started'; } /** * Determine if this step is in progress (Started state). * * @return boolean */ public function isFinished() { return $this->Status === "Finished"; } /** * Determine if the step has failed on its own (Failed state). No further state transitions may occur. * If Pipeline determines the step to be failed, all subsequent states will be aborted. * * @return boolean */ public function isFailed() { return $this->Status === "Failed"; } /** * Determine if the step has been aborted (Aborted state). * * @return boolean */ public function isAborted() { return $this->Status === "Aborted"; } /** * Log a message to the current log * * @param string $message */ public function log($message = "") { $this->Pipeline()->log($message); } /** * Tries to look up the value of the 'PerformTestOn' yml key for this step, and return the {@link DNEnvironment} * that the key refers to, if set. * * If the key isn't set, then it should return the current environment that the Pipeline is running for (e.g. * $this->Pipeline()->Environment()). * * @return DNEnvironment The dependent {@link DNEnvironment}. */ protected function getDependentEnvironment() { if($this->getConfigSetting('PerformTestOn') === 'DependentEnvironment') { try { $environment = $this->Pipeline()->getDependentEnvironment(); } catch(Exception $e) { $this->log($e->getMessage()); $this->markFailed(); return false; } } else { $environment = $this->Pipeline()->Environment(); } return $environment; } /** * Initialise the step unless it's already running (Started state). * The step will be expected to transition from here to Finished, Failed or Aborted state. * * @return boolean True if successfully started, false if error */ public function start() { $this->Status = 'Started'; $this->write(); } /** * Abort the step immediately, regardless of its current state, performing any cleanup necessary. * If a step is aborted, all subsequent states will also be aborted by the Pipeline, so it is possible * for a Queued step to skip straight to Aborted state. * * No further state transitions may occur. If aborting fails return false but remain in Aborted state. * * @return boolean True if successfully aborted, false if error */ public function abort() { if ($this->isQueued() || $this->isRunning()) { $this->Status = 'Aborted'; $this->log('Step aborted'); $this->write(); } return true; } /** * List of allowed actions the user is all allowed to take on this step * * @return array $options List of items, each as an associative array in the form * array( * 'action' => array( * 'ButtonText' => 'Action Title', * 'ButtonType' => 'btn-success', * 'Link' => 'naut/project/ss3/environment/deployuat/pipeline/1/step/action', * 'Title' => 'Action description', * 'Confirm' => 'Are you sure you wish to action?' * ) * ) */ public function allowedActions() { return array(); } public function getDryRun() { return $this->Pipeline()->DryRun; } } |