Source of file DeployForm.php
Size: 9,336 Bytes - Last Modified: 2021-12-23T10:29:15+00:00
/var/www/docs.ssmods.com/process/src/code/control/DeployForm.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 | <?php /** * Base class for a pipeline initiation validator * * @package deploynaut * @subpackage control */ abstract class DeployForm_ValidatorBase extends Validator { public function validationError($fieldName, $message, $messageType = '') { // Just make any error use the form message $this->form->sessionMessage($message, $messageType); parent::validationError($fieldName, $message, $messageType); } /** * Validate a commit sha * * @param string $sha * @return boolean */ protected function validateCommit($sha, $field) { // Check selected commit if(empty($sha)) { $this->validationError( $field, "No valid release selected", "required" ); return false; } // Check validity of commit if (!preg_match('/^[a-f0-9]{40}$/', $sha)) { $this->validationError( $field, "Invalid release SHA: " . Convert::raw2xml($sha), "error" ); return false; } return true; } } /** * Validates a multi-source commit selector * * @package deploynaut * @subpackage control */ class DeployForm_CommitValidator extends DeployForm_ValidatorBase { public function php($data) { // Check release method if(empty($data['SelectRelease']) || !in_array($data['SelectRelease'], array('Tag', 'Branch', 'Redeploy', 'SHA', 'FilteredCommits')) ) { $method = empty($data['SelectRelease']) ? '(blank)' : $data['SelectRelease']; $this->validationError( 'SelectRelease', "Bad release selection method: $method", "error" ); return false; } // Check sha return $this->validateCommit( $this->form->getSelectedBuild($data), 'SelectRelease' ); } } /** * Validates a pipeline commit selector * * @package deploynaut * @subpackage control */ class DeployForm_PipelineValidator extends DeployForm_ValidatorBase { public function php($data) { return $this->validateCommit( $this->form->getSelectedBuild($data), 'FilteredCommits' ); } } /** * Form for generating deployments from a specified commit * * @package deploynaut * @subpackage control */ class DeployForm extends Form { public function __construct($controller, $name, DNEnvironment $environment, DNProject $project) { if($environment->HasPipelineSupport()) { // Determine if commits are filtered $canBypass = Permission::check(DNRoot::DEPLOYNAUT_BYPASS_PIPELINE); $canDryrun = $environment->DryRunEnabled && Permission::check(DNRoot::DEPLOYNAUT_DRYRUN_PIPELINE); $commits = $environment->getDependentFilteredCommits(); if(empty($commits)) { // There are no filtered commits, so show all commits $field = $this->buildCommitSelector($project); $validator = new DeployForm_CommitValidator(); } elseif($canBypass) { // Build hybrid selector that allows users to follow pipeline or use any commit $field = $this->buildCommitSelector($project, $commits); $validator = new DeployForm_CommitValidator(); } else { // Restrict user to only select pipeline filtered commits $field = $this->buildPipelineField($commits); $validator = new DeployForm_PipelineValidator(); } $skipSnapshotTip = <<<END In the unusual occurence of your deployment containing database changes that are not reversible without a snapshot, rollback will not be able to restore your site proprely. The site will remain in maintenance mode - please contact the Service Desk for assistance. END; $fieldList = new FieldList(array( HeaderField::create('Label1', '1. Choose a commit to deploy', 4), $field, HeaderField::create('Label2', '2. Advanced options', 4), CheckboxField::create( 'SkipSnapshot', sprintf( 'Skip database snapshot and use existing database for rollbacks ' . '(<span class="tooltip-hint" href="#" data-toggle="tooltip" data-placement="bottom" title="%s">' . 'understand the risk' . '</span>)', $skipSnapshotTip ) ) )); // Generate actions allowed for this user $actions = new FieldList( FormAction::create('startPipeline', "Begin the release process on " . $environment->Name) ->addExtraClass('btn btn-primary') ->setAttribute('onclick', "return confirm('This will begin a release pipeline. Continue?');") ); if($canDryrun) { $actions->push( FormAction::create('doDryRun', "Dry-run release process") ->addExtraClass('btn btn-info') ->setAttribute('onclick', "return confirm('This will begin a release pipeline, but with the following exclusions:\\n" . " - No messages will be sent\\n" . " - No capistrano actions will be invoked\\n". " - No deployments or snapshots will be created.');" ) ); } if($canBypass) { $actions->push( FormAction::create('doDeploy', "Direct deployment (bypass pipeline)") ->addExtraClass('btn btn-warning') ->setAttribute('onclick', "return confirm('This will start a direct deployment, bypassing the pipeline ". "process in place.\\n\\nAre you sure this is necessary?');" ) ); } } else { // without a pipeline simply allow any commit to be selected $field = $this->buildCommitSelector($project); $validator = new DeployForm_CommitValidator(); $actions = new FieldList( FormAction::create('doDeploy', "Deploy to " . $environment->Name) ->addExtraClass('btn btn-primary') ->setAttribute('onclick', "return confirm('This will start a direct deployment.\\n\\nContinue?');" ) ); $fieldList = new FieldList($field); } parent::__construct($controller, $name, $fieldList, $actions, $validator); } /** * Construct fields to select any commit * * @param DNProject $project * @param DataList $pipelineCommits Optional list of pipeline-filtered commits to include * @return FormField */ protected function buildCommitSelector($project, $pipelineCommits = null) { // Branches $branches = array(); foreach($project->DNBranchList() as $branch) { $sha = $branch->SHA(); $name = $branch->Name(); $branches[$sha . '-' . $name] = $name . ' (' . substr($sha,0,8) . ', ' . $branch->LastUpdated()->TimeDiff() . ' old)'; } // Tags $tags = array(); foreach($project->DNTagList()->setLimit(null) as $tag) { $sha = $tag->SHA(); $name = $tag->Name(); $tags[$sha . '-' . $name] = $name . ' (' . substr($sha,0,8) . ', ' . $tag->Created()->TimeDiff() . ' old)'; } $tags = array_reverse($tags); // Past deployments $redeploy = array(); foreach($project->DNEnvironmentList() as $dnEnvironment) { $envName = $dnEnvironment->Name; foreach($dnEnvironment->DeployHistory() as $deploy) { $sha = $deploy->SHA; if(!isset($redeploy[$envName])) { $redeploy[$envName] = array(); } if(!isset($redeploy[$envName][$sha])) { $redeploy[$envName][$sha] = substr($sha,0,8) . ' (deployed ' . $deploy->obj('LastEdited')->Ago() . ')'; } } } // Merge fields $releaseMethods = array(); if($pipelineCommits) { $releaseMethods[] = new SelectionGroup_Item( 'FilteredCommits', $this->buildPipelineField($pipelineCommits), 'Deploy a commit prepared for this pipeline' ); } if($branches) { $releaseMethods[] = new SelectionGroup_Item( 'Branch', new DropdownField('Branch', '', $branches), 'Deploy the latest version of a branch' ); } if($tags) { $releaseMethods[] = new SelectionGroup_Item( 'Tag', new DropdownField('Tag', '', $tags), 'Deploy a tagged release' ); } if($redeploy) { $releaseMethods[] = new SelectionGroup_Item( 'Redeploy', new GroupedDropdownField('Redeploy', '', $redeploy), 'Redeploy a release that was previously deployed (to any environment)' ); } $releaseMethods[] = new SelectionGroup_Item( 'SHA', new Textfield('SHA', 'Please specify the full SHA'), 'Deploy a specific SHA' ); $field = new SelectionGroup('SelectRelease', $releaseMethods); $field->setValue(reset($releaseMethods)->getValue()); $field->addExtraClass('clearfix'); return $field; } /** * Generate fields necessary to select from a filtered commit list * * @param DNEnvironment $environment * @param DataList $commits List of commits * @return FormField */ protected function buildPipelineField($commits) { // Get filtered commits $filteredCommits = array(); foreach ($commits as $commit) { $title = sprintf( "%s (%s, %s old)", $commit->Message, substr($commit->SHA,0,8), $commit->dbObject('Created')->TimeDiff() ); $filteredCommits[$commit->SHA] = $title; } if($filteredCommits) { return new DropdownField('FilteredCommits', '', $filteredCommits); } else { return DropdownField::create('FilteredCommits)', '') ->setEmptyString('No deployments available') ->performDisabledTransformation(); } } /** * Get the build selected from the given data * * @param array $data * @return string SHA of selected build */ public function getSelectedBuild($data) { if(isset($data['SelectRelease']) && !empty($data[$data['SelectRelease']])) { // Filter out the tag/branch name if required $array = explode('-', $data[$data['SelectRelease']]); return reset($array); } if(isset($data['FilteredCommits']) && !empty($data['FilteredCommits'])) { return $data['FilteredCommits']; } } } |