Completed
Pull Request — master (#489)
by Helpful
03:51
created
code/model/steps/EmergencyRollbackStep.php 1 patch
Indentation   +167 added lines, -167 removed lines patch added patch discarded remove patch
@@ -26,171 +26,171 @@
 block discarded – undo
26 26
 class EmergencyRollbackStep extends LongRunningPipelineStep
27 27
 {
28 28
 
29
-    /**
30
-     * @var array
31
-     */
32
-    private static $db = array(
33
-        // if this has been rolled back set the date it was requested
34
-        'RolledBack' => "SS_Datetime"
35
-    );
36
-
37
-    /**
38
-     * @var array
39
-     */
40
-    private static $has_one = array(
41
-        'Responder' => 'Member'
42
-    );
43
-
44
-    /**
45
-     * @return bool
46
-     */
47
-    public function start()
48
-    {
49
-        // Just in case this step is being mistakenly restarted
50
-        if (!empty($this->RolledBack)) {
51
-            $this->log(_t('EmergencyRollbackStep.BEENROLLEDBACK',
52
-                "{$this->Title} has already been rolled back"));
53
-            $this->markFailed();
54
-            return false;
55
-        }
56
-
57
-        // check if we have timed out
58
-        if ($this->isTimedOut()) {
59
-            $this->log(sprintf(_t('EmergencyRollbackStep.ROLLBACKTIMEOUT',
60
-                "{$this->Title} is older than %s seconds and has timed out"),
61
-                $this->MaxDuration));
62
-            $this->finish();
63
-            return true;
64
-        }
65
-
66
-        // Begin or process this step
67
-        switch ($this->Status) {
68
-            case 'Started':
69
-                return true;
70
-            case 'Queued':
71
-                return $this->beginRollbackWindow();
72
-            default:
73
-                $this->log(_t('EmergencyRollbackStep.STARTERROR',
74
-                    "Unable to process {$this->Title} with status of {$this->Status}"));
75
-                $this->markFailed();
76
-                return false;
77
-        }
78
-    }
79
-
80
-    /**
81
-     * The user can do an emergency rollback if he could have deployed the code, or if he can abort pipelines.
82
-     *
83
-     * @param Member|null $member
84
-     * @return boolean
85
-     */
86
-    public function canTriggerRollback($member = null)
87
-    {
88
-        return $this->Pipeline()->Environment()->canDeploy($member) || $this->Pipeline()->canAbort($member);
89
-    }
90
-
91
-    /**
92
-     * When a member wishes to rollback this pipeline
93
-     *
94
-     * @return boolean True if successful
95
-     */
96
-    public function rollback()
97
-    {
98
-        // Check permission
99
-        if (!$this->canTriggerRollback()) {
100
-            return Security::permissionFailure(
101
-                null,
102
-                _t("EmergencyRollbackStep.DENYROLLBACKED",
103
-                "You do not have permission to rollback this pipeline")
104
-            );
105
-        }
106
-
107
-        if ($this->Status == 'Queued') {
108
-            $this->start();
109
-        }
110
-
111
-        // Write down some metadata.
112
-        $this->RolledBack = SS_Datetime::now()->Rfc2822();
113
-        $this->log(_t('EmergencyRollbackStep.BEINGROLLEDBACK', "{$this->Title} is being rolled back"));
114
-        $this->ResponderID = Member::currentUserID();
115
-        $this->write();
116
-
117
-        // Rollback itself is handled by the Pipeline object. This step will be marked as failed.
118
-        if ($this->Pipeline()->isRunning()) {
119
-            $this->Pipeline()->markFailed();
120
-            return true;
121
-        } else {
122
-            return false;
123
-        }
124
-    }
125
-
126
-    /**
127
-     * Dismiss the rollback window
128
-     */
129
-    public function dismiss()
130
-    {
131
-        // Check permission
132
-        if (!$this->canTriggerRollback()) {
133
-            return Security::permissionFailure(
134
-                null,
135
-                _t("EmergencyRollbackStep.DENYROLLBACKED",
136
-                "You do not have permission to rollback this pipeline")
137
-            );
138
-        }
139
-
140
-        $this->log("Dismissing rollback window.");
141
-        $this->finish();
142
-        return true;
143
-    }
144
-
145
-    /**
146
-     * Initiate the a rollback window
147
-     */
148
-    public function beginRollbackWindow()
149
-    {
150
-        $this->Status = 'Started';
151
-        if (!$this->Started) {
152
-            $this->Started = SS_Datetime::now()->Rfc2822();
153
-        }
154
-        $this->log(_t('EmergencyRollbackStep.BEGINROLLBACKWINDOW',
155
-            "{$this->Title} is beginning a rollback window..."));
156
-        $this->write();
157
-        // Message author that the deployment is complete
158
-        $this->Pipeline()->sendMessage(Pipeline::ALERT_SUCCESS);
159
-        return true;
160
-    }
161
-
162
-    public function getRunningDescription()
163
-    {
164
-        // Don't show options if this step has already been confirmed
165
-        if ($this->RolledBack) {
166
-            return;
167
-        }
168
-
169
-        return _t('EmergencyRollbackStep.RUNNINGDESCRIPTION',
170
-            'You may now roll back to the previous version, if needed.');
171
-    }
172
-
173
-    public function allowedActions()
174
-    {
175
-        // Don't show options if this step has already been confirmed or can't be confirmed
176
-        if (!$this->canTriggerRollback()) {
177
-            return parent::allowedActions();
178
-        }
179
-
180
-        // Return actions
181
-        return array(
182
-            'rollback' => array(
183
-                'ButtonText' => _t('EmergencyRollbackStep.ROLLBACKBUTTON', 'Rollback'),
184
-                'ButtonType' => 'btn-success',
185
-                'Link' => $this->Pipeline()->StepLink('rollback'),
186
-                'Title' => _t('EmergencyRollbackStep.ROLLBACKTHEDEPLOYMENTTITLE', 'Rollback the deployment')
187
-            ),
188
-            'dismiss' => array(
189
-                'ButtonText' => _t('EmergencyRollbackStep.DISMISS', 'Dismiss'),
190
-                'ButtonType' => 'btn-info',
191
-                'Link' => $this->Pipeline()->StepLink('dismiss'),
192
-                'Title' => _t('EmergencyRollbackStep.ROLLBACKTHEDEPLOYMENTTITLE', 'Dismiss this option')
193
-            )
194
-        );
195
-    }
29
+	/**
30
+	 * @var array
31
+	 */
32
+	private static $db = array(
33
+		// if this has been rolled back set the date it was requested
34
+		'RolledBack' => "SS_Datetime"
35
+	);
36
+
37
+	/**
38
+	 * @var array
39
+	 */
40
+	private static $has_one = array(
41
+		'Responder' => 'Member'
42
+	);
43
+
44
+	/**
45
+	 * @return bool
46
+	 */
47
+	public function start()
48
+	{
49
+		// Just in case this step is being mistakenly restarted
50
+		if (!empty($this->RolledBack)) {
51
+			$this->log(_t('EmergencyRollbackStep.BEENROLLEDBACK',
52
+				"{$this->Title} has already been rolled back"));
53
+			$this->markFailed();
54
+			return false;
55
+		}
56
+
57
+		// check if we have timed out
58
+		if ($this->isTimedOut()) {
59
+			$this->log(sprintf(_t('EmergencyRollbackStep.ROLLBACKTIMEOUT',
60
+				"{$this->Title} is older than %s seconds and has timed out"),
61
+				$this->MaxDuration));
62
+			$this->finish();
63
+			return true;
64
+		}
65
+
66
+		// Begin or process this step
67
+		switch ($this->Status) {
68
+			case 'Started':
69
+				return true;
70
+			case 'Queued':
71
+				return $this->beginRollbackWindow();
72
+			default:
73
+				$this->log(_t('EmergencyRollbackStep.STARTERROR',
74
+					"Unable to process {$this->Title} with status of {$this->Status}"));
75
+				$this->markFailed();
76
+				return false;
77
+		}
78
+	}
79
+
80
+	/**
81
+	 * The user can do an emergency rollback if he could have deployed the code, or if he can abort pipelines.
82
+	 *
83
+	 * @param Member|null $member
84
+	 * @return boolean
85
+	 */
86
+	public function canTriggerRollback($member = null)
87
+	{
88
+		return $this->Pipeline()->Environment()->canDeploy($member) || $this->Pipeline()->canAbort($member);
89
+	}
90
+
91
+	/**
92
+	 * When a member wishes to rollback this pipeline
93
+	 *
94
+	 * @return boolean True if successful
95
+	 */
96
+	public function rollback()
97
+	{
98
+		// Check permission
99
+		if (!$this->canTriggerRollback()) {
100
+			return Security::permissionFailure(
101
+				null,
102
+				_t("EmergencyRollbackStep.DENYROLLBACKED",
103
+				"You do not have permission to rollback this pipeline")
104
+			);
105
+		}
106
+
107
+		if ($this->Status == 'Queued') {
108
+			$this->start();
109
+		}
110
+
111
+		// Write down some metadata.
112
+		$this->RolledBack = SS_Datetime::now()->Rfc2822();
113
+		$this->log(_t('EmergencyRollbackStep.BEINGROLLEDBACK', "{$this->Title} is being rolled back"));
114
+		$this->ResponderID = Member::currentUserID();
115
+		$this->write();
116
+
117
+		// Rollback itself is handled by the Pipeline object. This step will be marked as failed.
118
+		if ($this->Pipeline()->isRunning()) {
119
+			$this->Pipeline()->markFailed();
120
+			return true;
121
+		} else {
122
+			return false;
123
+		}
124
+	}
125
+
126
+	/**
127
+	 * Dismiss the rollback window
128
+	 */
129
+	public function dismiss()
130
+	{
131
+		// Check permission
132
+		if (!$this->canTriggerRollback()) {
133
+			return Security::permissionFailure(
134
+				null,
135
+				_t("EmergencyRollbackStep.DENYROLLBACKED",
136
+				"You do not have permission to rollback this pipeline")
137
+			);
138
+		}
139
+
140
+		$this->log("Dismissing rollback window.");
141
+		$this->finish();
142
+		return true;
143
+	}
144
+
145
+	/**
146
+	 * Initiate the a rollback window
147
+	 */
148
+	public function beginRollbackWindow()
149
+	{
150
+		$this->Status = 'Started';
151
+		if (!$this->Started) {
152
+			$this->Started = SS_Datetime::now()->Rfc2822();
153
+		}
154
+		$this->log(_t('EmergencyRollbackStep.BEGINROLLBACKWINDOW',
155
+			"{$this->Title} is beginning a rollback window..."));
156
+		$this->write();
157
+		// Message author that the deployment is complete
158
+		$this->Pipeline()->sendMessage(Pipeline::ALERT_SUCCESS);
159
+		return true;
160
+	}
161
+
162
+	public function getRunningDescription()
163
+	{
164
+		// Don't show options if this step has already been confirmed
165
+		if ($this->RolledBack) {
166
+			return;
167
+		}
168
+
169
+		return _t('EmergencyRollbackStep.RUNNINGDESCRIPTION',
170
+			'You may now roll back to the previous version, if needed.');
171
+	}
172
+
173
+	public function allowedActions()
174
+	{
175
+		// Don't show options if this step has already been confirmed or can't be confirmed
176
+		if (!$this->canTriggerRollback()) {
177
+			return parent::allowedActions();
178
+		}
179
+
180
+		// Return actions
181
+		return array(
182
+			'rollback' => array(
183
+				'ButtonText' => _t('EmergencyRollbackStep.ROLLBACKBUTTON', 'Rollback'),
184
+				'ButtonType' => 'btn-success',
185
+				'Link' => $this->Pipeline()->StepLink('rollback'),
186
+				'Title' => _t('EmergencyRollbackStep.ROLLBACKTHEDEPLOYMENTTITLE', 'Rollback the deployment')
187
+			),
188
+			'dismiss' => array(
189
+				'ButtonText' => _t('EmergencyRollbackStep.DISMISS', 'Dismiss'),
190
+				'ButtonType' => 'btn-info',
191
+				'Link' => $this->Pipeline()->StepLink('dismiss'),
192
+				'Title' => _t('EmergencyRollbackStep.ROLLBACKTHEDEPLOYMENTTITLE', 'Dismiss this option')
193
+			)
194
+		);
195
+	}
196 196
 }
Please login to merge, or discard this patch.
code/model/steps/LongRunningPipelineStep.php 1 patch
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -12,58 +12,58 @@
 block discarded – undo
12 12
 class LongRunningPipelineStep extends PipelineStep
13 13
 {
14 14
 
15
-    /**
16
-     * Determines maximum allowed execution for deployment
17
-     *
18
-     * @return int Number of seconds, or null if not enabled
19
-     */
20
-    public function getMaxDuration()
21
-    {
22
-        return $this->getConfigSetting('MaxDuration') ?: null;
23
-    }
15
+	/**
16
+	 * Determines maximum allowed execution for deployment
17
+	 *
18
+	 * @return int Number of seconds, or null if not enabled
19
+	 */
20
+	public function getMaxDuration()
21
+	{
22
+		return $this->getConfigSetting('MaxDuration') ?: null;
23
+	}
24 24
 
25
-    /**
26
-     * @var array
27
-     */
28
-    private static $db = array(
29
-        'Started' => 'SS_Datetime'
30
-    );
25
+	/**
26
+	 * @var array
27
+	 */
28
+	private static $db = array(
29
+		'Started' => 'SS_Datetime'
30
+	);
31 31
 
32
-    /**
33
-     * Return true if this has timed out
34
-     *
35
-     * @return boolean
36
-     */
37
-    public function isTimedOut()
38
-    {
39
-        $age = $this->getAge();
40
-        $timeout = $this->getMaxDuration();
41
-        return $age && $timeout && ($age > $timeout);
42
-    }
32
+	/**
33
+	 * Return true if this has timed out
34
+	 *
35
+	 * @return boolean
36
+	 */
37
+	public function isTimedOut()
38
+	{
39
+		$age = $this->getAge();
40
+		$timeout = $this->getMaxDuration();
41
+		return $age && $timeout && ($age > $timeout);
42
+	}
43 43
 
44
-    /**
45
-     * Gets the age of this job in seconds, or 0 if not started
46
-     *
47
-     * @return int Age in seconds
48
-     */
49
-    public function getAge()
50
-    {
51
-        if ($this->Started) {
52
-            $started = intval($this->dbObject('Started')->Format('U'));
53
-            $now = intval(SS_Datetime::now()->Format('U'));
54
-            if ($started && $now) {
55
-                return $now - $started;
56
-            }
57
-        }
58
-        return 0;
59
-    }
44
+	/**
45
+	 * Gets the age of this job in seconds, or 0 if not started
46
+	 *
47
+	 * @return int Age in seconds
48
+	 */
49
+	public function getAge()
50
+	{
51
+		if ($this->Started) {
52
+			$started = intval($this->dbObject('Started')->Format('U'));
53
+			$now = intval(SS_Datetime::now()->Format('U'));
54
+			if ($started && $now) {
55
+				return $now - $started;
56
+			}
57
+		}
58
+		return 0;
59
+	}
60 60
 
61
-    public function start()
62
-    {
63
-        // Ensure started date is set
64
-        if (!$this->Started) {
65
-            $this->Started = SS_Datetime::now()->Rfc2822();
66
-            $this->write();
67
-        }
68
-    }
61
+	public function start()
62
+	{
63
+		// Ensure started date is set
64
+		if (!$this->Started) {
65
+			$this->Started = SS_Datetime::now()->Rfc2822();
66
+			$this->write();
67
+		}
68
+	}
69 69
 }
Please login to merge, or discard this patch.
code/model/steps/PipelineStep.php 1 patch
Indentation   +255 added lines, -255 removed lines patch added patch discarded remove patch
@@ -28,288 +28,288 @@
 block discarded – undo
28 28
 class PipelineStep extends DataObject implements PipelineData
29 29
 {
30 30
 
31
-    /**
32
-     * @var array
33
-     * - Order:  The order in which this step is to be executed within the {@link Pipeline}.
34
-     *           Links to the 'Pipeline' has_one below.
35
-     * - Status: The status if this particular step in the Pipeline. You can always query $this->Pipeline()->Status to
36
-     *           see the overall status of the pipeline itself.
37
-     */
38
-    private static $db = array(
39
-        'Name' => 'Varchar(255)',
40
-        'Order' => 'Int',
41
-        'Status' => 'Enum("Queued,Started,Finished,Failed,Aborted,n/a", "n/a")',
42
-        'Config' => 'Text' // serialized array of configuration for this step
43
-    );
31
+	/**
32
+	 * @var array
33
+	 * - Order:  The order in which this step is to be executed within the {@link Pipeline}.
34
+	 *           Links to the 'Pipeline' has_one below.
35
+	 * - Status: The status if this particular step in the Pipeline. You can always query $this->Pipeline()->Status to
36
+	 *           see the overall status of the pipeline itself.
37
+	 */
38
+	private static $db = array(
39
+		'Name' => 'Varchar(255)',
40
+		'Order' => 'Int',
41
+		'Status' => 'Enum("Queued,Started,Finished,Failed,Aborted,n/a", "n/a")',
42
+		'Config' => 'Text' // serialized array of configuration for this step
43
+	);
44 44
 
45
-    private static $has_one = array(
46
-        'Pipeline' => 'Pipeline'
47
-    );
45
+	private static $has_one = array(
46
+		'Pipeline' => 'Pipeline'
47
+	);
48 48
 
49
-    /**
50
-     * @var string Ensure we use the 'Order' int as the sort order. This means that all code that references
51
-     * {@link Pipeline::PipelineSteps()} will always get the steps in the same order.
52
-     */
53
-    private static $default_sort = 'Order';
49
+	/**
50
+	 * @var string Ensure we use the 'Order' int as the sort order. This means that all code that references
51
+	 * {@link Pipeline::PipelineSteps()} will always get the steps in the same order.
52
+	 */
53
+	private static $default_sort = 'Order';
54 54
 
55
-    private static $summary_fields = array(
56
-        'Name',
57
-        'Status',
58
-        'LastEdited'
59
-    );
55
+	private static $summary_fields = array(
56
+		'Name',
57
+		'Status',
58
+		'LastEdited'
59
+	);
60 60
 
61
-    /**
62
-     * Cached of config merged with defaults
63
-     *
64
-     * @var array|null
65
-     */
66
-    protected $mergedConfig;
61
+	/**
62
+	 * Cached of config merged with defaults
63
+	 *
64
+	 * @var array|null
65
+	 */
66
+	protected $mergedConfig;
67 67
 
68
-    /**
69
-     * Title of this step
70
-     *
71
-     * @return string
72
-     */
73
-    public function getTitle()
74
-    {
75
-        return $this->Name ?: get_class($this);
76
-    }
68
+	/**
69
+	 * Title of this step
70
+	 *
71
+	 * @return string
72
+	 */
73
+	public function getTitle()
74
+	{
75
+		return $this->Name ?: get_class($this);
76
+	}
77 77
 
78
-    public function getTreeTitle()
79
-    {
80
-        return $this->Title . ' (Status: ' . $this->Status . ')';
81
-    }
78
+	public function getTreeTitle()
79
+	{
80
+		return $this->Title . ' (Status: ' . $this->Status . ')';
81
+	}
82 82
 
83
-    public function getNiceName()
84
-    {
85
-        $niceName = $this->getConfigSetting('NiceName')
86
-            ?: ucwords(trim(strtolower(preg_replace('/_?([A-Z])/', ' $1', $this->getTitle()))));
83
+	public function getNiceName()
84
+	{
85
+		$niceName = $this->getConfigSetting('NiceName')
86
+			?: ucwords(trim(strtolower(preg_replace('/_?([A-Z])/', ' $1', $this->getTitle()))));
87 87
 
88
-        if ($this->isFinished()) {
89
-            $niceName = $this->getConfigSetting('NiceDone') ?: $niceName;
90
-        }
88
+		if ($this->isFinished()) {
89
+			$niceName = $this->getConfigSetting('NiceDone') ?: $niceName;
90
+		}
91 91
 
92
-        return $niceName;
93
-    }
92
+		return $niceName;
93
+	}
94 94
 
95
-    /**
96
-     * Unserializes a snippet of configuration that was saved at the time this step
97
-     * was created at {@link Pipeline::start()} so that this step can use that configuration
98
-     * to determine what it needs to do. e.g for SmokeTestPipelineStep this might contain
99
-     * a list of URLs that need to be checked and which status codes to check for.
100
-     *
101
-     * @return array
102
-     */
103
-    public function getConfigData()
104
-    {
105
-        if (!$this->Config) {
106
-            return array();
107
-        }
95
+	/**
96
+	 * Unserializes a snippet of configuration that was saved at the time this step
97
+	 * was created at {@link Pipeline::start()} so that this step can use that configuration
98
+	 * to determine what it needs to do. e.g for SmokeTestPipelineStep this might contain
99
+	 * a list of URLs that need to be checked and which status codes to check for.
100
+	 *
101
+	 * @return array
102
+	 */
103
+	public function getConfigData()
104
+	{
105
+		if (!$this->Config) {
106
+			return array();
107
+		}
108 108
 
109
-        // Merge with defaults
110
-        if (!$this->mergedConfig) {
111
-            $this->mergedConfig = unserialize($this->Config);
112
-            if ($default = self::config()->default_config) {
113
-                Config::merge_array_low_into_high($this->mergedConfig, $default);
114
-            }
115
-        }
116
-        return $this->mergedConfig;
117
-    }
109
+		// Merge with defaults
110
+		if (!$this->mergedConfig) {
111
+			$this->mergedConfig = unserialize($this->Config);
112
+			if ($default = self::config()->default_config) {
113
+				Config::merge_array_low_into_high($this->mergedConfig, $default);
114
+			}
115
+		}
116
+		return $this->mergedConfig;
117
+	}
118 118
 
119
-    public function setConfig($data)
120
-    {
121
-        $this->mergedConfig = null;
122
-        return parent::setField('Config', $data);
123
-    }
119
+	public function setConfig($data)
120
+	{
121
+		$this->mergedConfig = null;
122
+		return parent::setField('Config', $data);
123
+	}
124 124
 
125
-    /**
126
-     * Describe what the step is currently doing.
127
-     *
128
-     * @return string
129
-     */
130
-    public function getRunningDescription()
131
-    {
132
-        return '';
133
-    }
125
+	/**
126
+	 * Describe what the step is currently doing.
127
+	 *
128
+	 * @return string
129
+	 */
130
+	public function getRunningDescription()
131
+	{
132
+		return '';
133
+	}
134 134
 
135
-    /**
136
-     * Retrieve the value of a specific config setting
137
-     *
138
-     * @param string $setting Settings
139
-     * @return mixed Value of setting, or null if not set
140
-     */
141
-    public function getConfigSetting($setting)
142
-    {
143
-        $source = $this->getConfigData();
144
-        foreach (func_get_args() as $setting) {
145
-            if (empty($source[$setting])) {
146
-                return null;
147
-            }
148
-            $source = $source[$setting];
149
-        }
150
-        return $source;
151
-    }
135
+	/**
136
+	 * Retrieve the value of a specific config setting
137
+	 *
138
+	 * @param string $setting Settings
139
+	 * @return mixed Value of setting, or null if not set
140
+	 */
141
+	public function getConfigSetting($setting)
142
+	{
143
+		$source = $this->getConfigData();
144
+		foreach (func_get_args() as $setting) {
145
+			if (empty($source[$setting])) {
146
+				return null;
147
+			}
148
+			$source = $source[$setting];
149
+		}
150
+		return $source;
151
+	}
152 152
 
153
-    public function finish()
154
-    {
155
-        $this->Status = 'Finished';
156
-        $this->log('Step finished successfully!');
157
-        $this->write();
158
-    }
153
+	public function finish()
154
+	{
155
+		$this->Status = 'Finished';
156
+		$this->log('Step finished successfully!');
157
+		$this->write();
158
+	}
159 159
 
160
-    /**
161
-     * Fail this pipeline step
162
-     *
163
-     * @param bool $notify Set to false to disable notifications for this failure
164
-     */
165
-    public function markFailed($notify = true)
166
-    {
167
-        $this->Status = 'Failed';
168
-        $this->log('Marking pipeline step as failed. See earlier log messages to determine cause.');
169
-        $this->write();
170
-        $this->Pipeline()->markFailed($notify);
171
-    }
160
+	/**
161
+	 * Fail this pipeline step
162
+	 *
163
+	 * @param bool $notify Set to false to disable notifications for this failure
164
+	 */
165
+	public function markFailed($notify = true)
166
+	{
167
+		$this->Status = 'Failed';
168
+		$this->log('Marking pipeline step as failed. See earlier log messages to determine cause.');
169
+		$this->write();
170
+		$this->Pipeline()->markFailed($notify);
171
+	}
172 172
 
173
-    /**
174
-     * Determine if this step is in progress (Started state).
175
-     *
176
-     * @return boolean
177
-     */
178
-    public function isQueued()
179
-    {
180
-        return $this->Status === 'Queued';
181
-    }
173
+	/**
174
+	 * Determine if this step is in progress (Started state).
175
+	 *
176
+	 * @return boolean
177
+	 */
178
+	public function isQueued()
179
+	{
180
+		return $this->Status === 'Queued';
181
+	}
182 182
 
183
-    /**
184
-     * Determine if this step is in progress (Started state).
185
-     *
186
-     * @return boolean
187
-     */
188
-    public function isRunning()
189
-    {
190
-        return $this->Status === 'Started';
191
-    }
183
+	/**
184
+	 * Determine if this step is in progress (Started state).
185
+	 *
186
+	 * @return boolean
187
+	 */
188
+	public function isRunning()
189
+	{
190
+		return $this->Status === 'Started';
191
+	}
192 192
 
193
-    /**
194
-     * Determine if this step is in progress (Started state).
195
-     *
196
-     * @return boolean
197
-     */
198
-    public function isFinished()
199
-    {
200
-        return $this->Status === "Finished";
201
-    }
193
+	/**
194
+	 * Determine if this step is in progress (Started state).
195
+	 *
196
+	 * @return boolean
197
+	 */
198
+	public function isFinished()
199
+	{
200
+		return $this->Status === "Finished";
201
+	}
202 202
 
203
-    /**
204
-     * Determine if the step has failed on its own (Failed state). No further state transitions may occur.
205
-     * If Pipeline determines the step to be failed, all subsequent states will be aborted.
206
-     *
207
-     * @return boolean
208
-     */
209
-    public function isFailed()
210
-    {
211
-        return $this->Status === "Failed";
212
-    }
203
+	/**
204
+	 * Determine if the step has failed on its own (Failed state). No further state transitions may occur.
205
+	 * If Pipeline determines the step to be failed, all subsequent states will be aborted.
206
+	 *
207
+	 * @return boolean
208
+	 */
209
+	public function isFailed()
210
+	{
211
+		return $this->Status === "Failed";
212
+	}
213 213
 
214
-    /**
215
-     * Determine if the step has been aborted (Aborted state).
216
-     *
217
-     * @return boolean
218
-     */
219
-    public function isAborted()
220
-    {
221
-        return $this->Status === "Aborted";
222
-    }
214
+	/**
215
+	 * Determine if the step has been aborted (Aborted state).
216
+	 *
217
+	 * @return boolean
218
+	 */
219
+	public function isAborted()
220
+	{
221
+		return $this->Status === "Aborted";
222
+	}
223 223
 
224
-    /**
225
-     * Log a message to the current log
226
-     *
227
-     * @param string $message
228
-     */
229
-    public function log($message = "")
230
-    {
231
-        $this->Pipeline()->log($message);
232
-    }
224
+	/**
225
+	 * Log a message to the current log
226
+	 *
227
+	 * @param string $message
228
+	 */
229
+	public function log($message = "")
230
+	{
231
+		$this->Pipeline()->log($message);
232
+	}
233 233
 
234
-    /**
235
-     * Tries to look up the value of the 'PerformTestOn' yml key for this step, and return the {@link DNEnvironment}
236
-     * that the key refers to, if set.
237
-     *
238
-     * If the key isn't set, then it should return the current environment that the Pipeline is running for (e.g.
239
-     * $this->Pipeline()->Environment()).
240
-     *
241
-     * @return DNEnvironment The dependent {@link DNEnvironment}.
242
-     */
243
-    protected function getDependentEnvironment()
244
-    {
245
-        if ($this->getConfigSetting('PerformTestOn') === 'DependentEnvironment') {
246
-            try {
247
-                $environment = $this->Pipeline()->getDependentEnvironment();
248
-            } catch (Exception $e) {
249
-                $this->log($e->getMessage());
250
-                $this->markFailed();
251
-                return false;
252
-            }
253
-        } else {
254
-            $environment = $this->Pipeline()->Environment();
255
-        }
234
+	/**
235
+	 * Tries to look up the value of the 'PerformTestOn' yml key for this step, and return the {@link DNEnvironment}
236
+	 * that the key refers to, if set.
237
+	 *
238
+	 * If the key isn't set, then it should return the current environment that the Pipeline is running for (e.g.
239
+	 * $this->Pipeline()->Environment()).
240
+	 *
241
+	 * @return DNEnvironment The dependent {@link DNEnvironment}.
242
+	 */
243
+	protected function getDependentEnvironment()
244
+	{
245
+		if ($this->getConfigSetting('PerformTestOn') === 'DependentEnvironment') {
246
+			try {
247
+				$environment = $this->Pipeline()->getDependentEnvironment();
248
+			} catch (Exception $e) {
249
+				$this->log($e->getMessage());
250
+				$this->markFailed();
251
+				return false;
252
+			}
253
+		} else {
254
+			$environment = $this->Pipeline()->Environment();
255
+		}
256 256
 
257
-        return $environment;
258
-    }
257
+		return $environment;
258
+	}
259 259
 
260
-    /**
261
-     * Initialise the step unless it's already running (Started state).
262
-     * The step will be expected to transition from here to Finished, Failed or Aborted state.
263
-     *
264
-     * @return boolean|null True if successfully started, false if error
265
-     */
266
-    public function start()
267
-    {
268
-        $this->Status = 'Started';
269
-        $this->write();
270
-    }
260
+	/**
261
+	 * Initialise the step unless it's already running (Started state).
262
+	 * The step will be expected to transition from here to Finished, Failed or Aborted state.
263
+	 *
264
+	 * @return boolean|null True if successfully started, false if error
265
+	 */
266
+	public function start()
267
+	{
268
+		$this->Status = 'Started';
269
+		$this->write();
270
+	}
271 271
 
272
-    /**
273
-     * Abort the step immediately, regardless of its current state, performing any cleanup necessary.
274
-     * If a step is aborted, all subsequent states will also be aborted by the Pipeline, so it is possible
275
-     * for a Queued step to skip straight to Aborted state.
276
-     *
277
-     * No further state transitions may occur. If aborting fails return false but remain in Aborted state.
278
-     *
279
-     * @return boolean True if successfully aborted, false if error
280
-     */
281
-    public function abort()
282
-    {
283
-        if ($this->isQueued() || $this->isRunning()) {
284
-            $this->Status = 'Aborted';
285
-            $this->log('Step aborted');
286
-            $this->write();
287
-        }
272
+	/**
273
+	 * Abort the step immediately, regardless of its current state, performing any cleanup necessary.
274
+	 * If a step is aborted, all subsequent states will also be aborted by the Pipeline, so it is possible
275
+	 * for a Queued step to skip straight to Aborted state.
276
+	 *
277
+	 * No further state transitions may occur. If aborting fails return false but remain in Aborted state.
278
+	 *
279
+	 * @return boolean True if successfully aborted, false if error
280
+	 */
281
+	public function abort()
282
+	{
283
+		if ($this->isQueued() || $this->isRunning()) {
284
+			$this->Status = 'Aborted';
285
+			$this->log('Step aborted');
286
+			$this->write();
287
+		}
288 288
 
289
-        return true;
290
-    }
289
+		return true;
290
+	}
291 291
 
292
-    /**
293
-     * List of allowed actions the user is all allowed to take on this step
294
-     *
295
-     * @return array $options List of items, each as an associative array in the form
296
-     * array(
297
-     *     'action' => array(
298
-     *         'ButtonText' => 'Action Title',
299
-     *         'ButtonType' => 'btn-success',
300
-     *         'Link' => 'naut/project/ss3/environment/deployuat/pipeline/1/step/action',
301
-     *         'Title' => 'Action description',
302
-     *         'Confirm' => 'Are you sure you wish to action?'
303
-     *     )
304
-     * )
305
-     */
306
-    public function allowedActions()
307
-    {
308
-        return array();
309
-    }
292
+	/**
293
+	 * List of allowed actions the user is all allowed to take on this step
294
+	 *
295
+	 * @return array $options List of items, each as an associative array in the form
296
+	 * array(
297
+	 *     'action' => array(
298
+	 *         'ButtonText' => 'Action Title',
299
+	 *         'ButtonType' => 'btn-success',
300
+	 *         'Link' => 'naut/project/ss3/environment/deployuat/pipeline/1/step/action',
301
+	 *         'Title' => 'Action description',
302
+	 *         'Confirm' => 'Are you sure you wish to action?'
303
+	 *     )
304
+	 * )
305
+	 */
306
+	public function allowedActions()
307
+	{
308
+		return array();
309
+	}
310 310
 
311
-    public function getDryRun()
312
-    {
313
-        return $this->Pipeline()->DryRun;
314
-    }
311
+	public function getDryRun()
312
+	{
313
+		return $this->Pipeline()->DryRun;
314
+	}
315 315
 }
Please login to merge, or discard this patch.
code/model/steps/RollbackStep.php 1 patch
Indentation   +233 added lines, -233 removed lines patch added patch discarded remove patch
@@ -25,263 +25,263 @@
 block discarded – undo
25 25
 class RollbackStep extends LongRunningPipelineStep
26 26
 {
27 27
 
28
-    /**
29
-     * @var array
30
-     */
31
-    private static $db = array(
32
-        'Doing' => "Enum('Deployment,Snapshot,Queued', 'Queued')"
33
-    );
28
+	/**
29
+	 * @var array
30
+	 */
31
+	private static $db = array(
32
+		'Doing' => "Enum('Deployment,Snapshot,Queued', 'Queued')"
33
+	);
34 34
 
35
-    /**
36
-     * @var array
37
-     */
38
-    private static $has_one = array(
39
-        'RollbackDeployment' => 'DNDeployment',
40
-        'RollbackDatabase' => 'DNDataTransfer'
41
-    );
35
+	/**
36
+	 * @var array
37
+	 */
38
+	private static $has_one = array(
39
+		'RollbackDeployment' => 'DNDeployment',
40
+		'RollbackDatabase' => 'DNDataTransfer'
41
+	);
42 42
 
43
-    /**
44
-     * @return string
45
-     */
46
-    public function getTitle()
47
-    {
48
-        // Make sure the title includes the subtask
49
-        return parent::getTitle() . ":{$this->Doing}";
50
-    }
43
+	/**
44
+	 * @return string
45
+	 */
46
+	public function getTitle()
47
+	{
48
+		// Make sure the title includes the subtask
49
+		return parent::getTitle() . ":{$this->Doing}";
50
+	}
51 51
 
52
-    /**
53
-     * @return bool|null
54
-     */
55
-    public function start()
56
-    {
57
-        parent::start();
52
+	/**
53
+	 * @return bool|null
54
+	 */
55
+	public function start()
56
+	{
57
+		parent::start();
58 58
 
59
-        switch ($this->Status) {
60
-            case 'Started':
61
-                // If we are doing a subtask, check which one to continue
62
-                switch ($this->Doing) {
63
-                    case 'Deployment':
64
-                        return $this->continueRevertDeploy();
65
-                    case 'Snapshot':
66
-                        return $this->continueRevertDatabase();
67
-                    default:
68
-                        $this->log("Unable to process {$this->Title} with subtask of {$this->Doing}");
69
-                        $this->markFailed();
70
-                        return false;
71
-                }
72
-            case 'Queued':
73
-                // Begin rollback by initiating deployment
74
-                return $this->startRevertDeploy();
75
-            default:
76
-                $this->log("Unable to process {$this->Title} with status of {$this->Status}");
77
-                $this->markFailed();
78
-                return false;
79
-        }
80
-    }
59
+		switch ($this->Status) {
60
+			case 'Started':
61
+				// If we are doing a subtask, check which one to continue
62
+				switch ($this->Doing) {
63
+					case 'Deployment':
64
+						return $this->continueRevertDeploy();
65
+					case 'Snapshot':
66
+						return $this->continueRevertDatabase();
67
+					default:
68
+						$this->log("Unable to process {$this->Title} with subtask of {$this->Doing}");
69
+						$this->markFailed();
70
+						return false;
71
+				}
72
+			case 'Queued':
73
+				// Begin rollback by initiating deployment
74
+				return $this->startRevertDeploy();
75
+			default:
76
+				$this->log("Unable to process {$this->Title} with status of {$this->Status}");
77
+				$this->markFailed();
78
+				return false;
79
+		}
80
+	}
81 81
 
82
-    /**
83
-     * Begin a new deployment
84
-     *
85
-     * @return boolean
86
-     */
87
-    protected function startRevertDeploy()
88
-    {
89
-        $this->Status = 'Started';
90
-        $this->Doing = 'Deployment';
91
-        $this->log("{$this->Title} starting revert deployment");
82
+	/**
83
+	 * Begin a new deployment
84
+	 *
85
+	 * @return boolean
86
+	 */
87
+	protected function startRevertDeploy()
88
+	{
89
+		$this->Status = 'Started';
90
+		$this->Doing = 'Deployment';
91
+		$this->log("{$this->Title} starting revert deployment");
92 92
 
93
-        // Skip deployment for dry run
94
-        if ($this->Pipeline()->DryRun) {
95
-            $this->log("[Skipped] Create DNDeployment");
96
-            $this->write();
97
-            return true;
98
-        }
93
+		// Skip deployment for dry run
94
+		if ($this->Pipeline()->DryRun) {
95
+			$this->log("[Skipped] Create DNDeployment");
96
+			$this->write();
97
+			return true;
98
+		}
99 99
 
100
-        // Get old deployment from pipeline
101
-        $pipeline = $this->Pipeline();
102
-        $previous = $pipeline->PreviousDeployment();
103
-        if (empty($previous) || empty($previous->SHA)) {
104
-            $this->log("No available SHA for {$this->Title}");
105
-            $this->markFailed();
106
-            return false;
107
-        }
100
+		// Get old deployment from pipeline
101
+		$pipeline = $this->Pipeline();
102
+		$previous = $pipeline->PreviousDeployment();
103
+		if (empty($previous) || empty($previous->SHA)) {
104
+			$this->log("No available SHA for {$this->Title}");
105
+			$this->markFailed();
106
+			return false;
107
+		}
108 108
 
109
-        // Initialise deployment
110
-        $strategy = new DeploymentStrategy($pipeline->Environment(), array(
111
-            'sha'=>$pipeline->SHA,
112
-            // Leave the maintenance page up if we are restoring the DB
113
-            'leaveMaintenancePage' => $this->doRestoreDB()
114
-        ));
115
-        $deployment = $strategy->createDeployment();
109
+		// Initialise deployment
110
+		$strategy = new DeploymentStrategy($pipeline->Environment(), array(
111
+			'sha'=>$pipeline->SHA,
112
+			// Leave the maintenance page up if we are restoring the DB
113
+			'leaveMaintenancePage' => $this->doRestoreDB()
114
+		));
115
+		$deployment = $strategy->createDeployment();
116 116
 
117
-        $deployment->DeployerID = $pipeline->AuthorID;
118
-        $deployment->write();
119
-        $deployment->start();
120
-        $this->RollbackDeploymentID = $deployment->ID;
121
-        $this->write();
117
+		$deployment->DeployerID = $pipeline->AuthorID;
118
+		$deployment->write();
119
+		$deployment->start();
120
+		$this->RollbackDeploymentID = $deployment->ID;
121
+		$this->write();
122 122
 
123
-        return true;
124
-    }
123
+		return true;
124
+	}
125 125
 
126
-    /**
127
-     * Create a snapshot of the db and store the ID on the Pipline
128
-     *
129
-     * @return bool True if success
130
-     */
131
-    protected function startRevertDatabase()
132
-    {
133
-        // Mark self as creating a snapshot
134
-        $this->Status = 'Started';
135
-        $this->Doing = 'Snapshot';
136
-        $this->log("{$this->Title} reverting database from snapshot");
126
+	/**
127
+	 * Create a snapshot of the db and store the ID on the Pipline
128
+	 *
129
+	 * @return bool True if success
130
+	 */
131
+	protected function startRevertDatabase()
132
+	{
133
+		// Mark self as creating a snapshot
134
+		$this->Status = 'Started';
135
+		$this->Doing = 'Snapshot';
136
+		$this->log("{$this->Title} reverting database from snapshot");
137 137
 
138
-        // Skip deployment for dry run
139
-        if ($this->Pipeline()->DryRun) {
140
-            $this->write();
141
-            $this->log("[Skipped] Create DNDataTransfer restore");
142
-            return true;
143
-        }
138
+		// Skip deployment for dry run
139
+		if ($this->Pipeline()->DryRun) {
140
+			$this->write();
141
+			$this->log("[Skipped] Create DNDataTransfer restore");
142
+			return true;
143
+		}
144 144
 
145
-        // Get snapshot
146
-        $pipeline = $this->Pipeline();
147
-        $backup = $pipeline->PreviousSnapshot();
148
-        if (empty($backup) || !$backup->exists()) {
149
-            $this->log("No database to revert for {$this->Title}");
150
-            $this->markFailed();
151
-            return false;
152
-        }
145
+		// Get snapshot
146
+		$pipeline = $this->Pipeline();
147
+		$backup = $pipeline->PreviousSnapshot();
148
+		if (empty($backup) || !$backup->exists()) {
149
+			$this->log("No database to revert for {$this->Title}");
150
+			$this->markFailed();
151
+			return false;
152
+		}
153 153
 
154
-        // Create restore job
155
-        $job = DNDataTransfer::create();
156
-        $job->EnvironmentID = $pipeline->EnvironmentID;
157
-        $job->Direction = 'push';
158
-        $job->Mode = 'db';
159
-        $job->DataArchiveID = $backup->DataArchiveID;
160
-        $job->AuthorID = $pipeline->AuthorID;
161
-        $job->EnvironmentID = $pipeline->EnvironmentID;
162
-        $job->write();
163
-        $job->start();
154
+		// Create restore job
155
+		$job = DNDataTransfer::create();
156
+		$job->EnvironmentID = $pipeline->EnvironmentID;
157
+		$job->Direction = 'push';
158
+		$job->Mode = 'db';
159
+		$job->DataArchiveID = $backup->DataArchiveID;
160
+		$job->AuthorID = $pipeline->AuthorID;
161
+		$job->EnvironmentID = $pipeline->EnvironmentID;
162
+		$job->write();
163
+		$job->start();
164 164
 
165
-        // Save rollback
166
-        $this->RollbackDatabaseID = $job->ID;
167
-        $this->write();
168
-        return true;
169
-    }
165
+		// Save rollback
166
+		$this->RollbackDatabaseID = $job->ID;
167
+		$this->write();
168
+		return true;
169
+	}
170 170
 
171
-    /**
172
-     * Check status of current snapshot
173
-     */
174
-    protected function continueRevertDatabase()
175
-    {
176
-        $this->log("Checking status of {$this->Title}...");
171
+	/**
172
+	 * Check status of current snapshot
173
+	 */
174
+	protected function continueRevertDatabase()
175
+	{
176
+		$this->log("Checking status of {$this->Title}...");
177 177
 
178
-        // Skip snapshot for dry run
179
-        if ($this->Pipeline()->DryRun) {
180
-            $this->log("[Skipped] Checking progress of snapshot restore");
181
-            return $this->finish();
182
-        }
178
+		// Skip snapshot for dry run
179
+		if ($this->Pipeline()->DryRun) {
180
+			$this->log("[Skipped] Checking progress of snapshot restore");
181
+			return $this->finish();
182
+		}
183 183
 
184
-        // Get related snapshot
185
-        $transfer = $this->RollbackDatabase();
186
-        if (empty($transfer) || !$transfer->exists()) {
187
-            $this->log("Missing database transfer for in-progress {$this->Title}");
188
-            $this->markFailed();
189
-            return false;
190
-        }
184
+		// Get related snapshot
185
+		$transfer = $this->RollbackDatabase();
186
+		if (empty($transfer) || !$transfer->exists()) {
187
+			$this->log("Missing database transfer for in-progress {$this->Title}");
188
+			$this->markFailed();
189
+			return false;
190
+		}
191 191
 
192
-        // Check finished state
193
-        $status = $transfer->ResqueStatus();
194
-        if ($this->checkResqueStatus($status)) {
195
-            // Re-enable the site by disabling the maintenance, since the DB restored successfully
196
-            $this->Pipeline()->Environment()->disableMaintenance($this->Pipeline()->getLogger());
192
+		// Check finished state
193
+		$status = $transfer->ResqueStatus();
194
+		if ($this->checkResqueStatus($status)) {
195
+			// Re-enable the site by disabling the maintenance, since the DB restored successfully
196
+			$this->Pipeline()->Environment()->disableMaintenance($this->Pipeline()->getLogger());
197 197
 
198
-            // After revert is complete we are done
199
-            return $this->finish();
200
-        }
201
-    }
198
+			// After revert is complete we are done
199
+			return $this->finish();
200
+		}
201
+	}
202 202
 
203
-    /**
204
-     * Check status of deployment and finish task if complete, or fail if timedout
205
-     *
206
-     * @return boolean
207
-     */
208
-    protected function continueRevertDeploy()
209
-    {
210
-        $this->log("Checking status of {$this->Title}...");
203
+	/**
204
+	 * Check status of deployment and finish task if complete, or fail if timedout
205
+	 *
206
+	 * @return boolean
207
+	 */
208
+	protected function continueRevertDeploy()
209
+	{
210
+		$this->log("Checking status of {$this->Title}...");
211 211
 
212
-        // Skip deployment for dry run
213
-        if ($this->Pipeline()->DryRun) {
214
-            $this->log("[Skipped] Checking progress of deployment");
215
-            if ($this->getConfigSetting('RestoreDB')) {
216
-                return $this->startRevertDatabase();
217
-            } else {
218
-                $this->finish();
219
-                return true;
220
-            }
221
-        }
212
+		// Skip deployment for dry run
213
+		if ($this->Pipeline()->DryRun) {
214
+			$this->log("[Skipped] Checking progress of deployment");
215
+			if ($this->getConfigSetting('RestoreDB')) {
216
+				return $this->startRevertDatabase();
217
+			} else {
218
+				$this->finish();
219
+				return true;
220
+			}
221
+		}
222 222
 
223
-        // Get related deployment
224
-        $deployment = $this->RollbackDeployment();
225
-        if (empty($deployment) || !$deployment->exists()) {
226
-            $this->log("Missing deployment for in-progress {$this->Title}");
227
-            $this->markFailed();
228
-            return false;
229
-        }
223
+		// Get related deployment
224
+		$deployment = $this->RollbackDeployment();
225
+		if (empty($deployment) || !$deployment->exists()) {
226
+			$this->log("Missing deployment for in-progress {$this->Title}");
227
+			$this->markFailed();
228
+			return false;
229
+		}
230 230
 
231
-        // Check finished state
232
-        $status = $deployment->ResqueStatus();
233
-        if ($this->checkResqueStatus($status)) {
234
-            // Since deployment is finished, check if we should also do a db restoration
235
-            if ($this->doRestoreDB()) {
236
-                return $this->startRevertDatabase();
237
-            } else {
238
-                $this->finish();
239
-            }
240
-        }
241
-        return !$this->isFailed();
242
-    }
231
+		// Check finished state
232
+		$status = $deployment->ResqueStatus();
233
+		if ($this->checkResqueStatus($status)) {
234
+			// Since deployment is finished, check if we should also do a db restoration
235
+			if ($this->doRestoreDB()) {
236
+				return $this->startRevertDatabase();
237
+			} else {
238
+				$this->finish();
239
+			}
240
+		}
241
+		return !$this->isFailed();
242
+	}
243 243
 
244
-    /**
245
-     * Check if we are intending to restore the DB after this deployment
246
-     *
247
-     * @return boolean
248
-     */
249
-    protected function doRestoreDB()
250
-    {
251
-        return $this->getConfigSetting('RestoreDB') && $this->Pipeline()->PreviousSnapshot();
252
-    }
244
+	/**
245
+	 * Check if we are intending to restore the DB after this deployment
246
+	 *
247
+	 * @return boolean
248
+	 */
249
+	protected function doRestoreDB()
250
+	{
251
+		return $this->getConfigSetting('RestoreDB') && $this->Pipeline()->PreviousSnapshot();
252
+	}
253 253
 
254
-    /**
255
-     * Check the status of a resque sub-task
256
-     *
257
-     * @param string $status Resque task status
258
-     * @return boolean True if the task is finished successfully
259
-     */
260
-    protected function checkResqueStatus($status)
261
-    {
262
-        switch ($status) {
263
-            case "Complete":
264
-                return true;
265
-            case "Failed":
266
-            case "Invalid":
267
-                $this->log("{$this->Title} failed with task status $status");
268
-                $this->markFailed();
269
-                return false;
270
-            case "Queued":
271
-            case "Running":
272
-            default:
273
-                // For running or queued tasks ensure that we have not exceeded
274
-                // a reasonable time-elapsed to consider this job inactive
275
-                if ($this->isTimedOut()) {
276
-                    $this->log("{$this->Title} took longer than {$this->MaxDuration} seconds to run and has timed out");
277
-                    $this->markFailed();
278
-                    return false;
279
-                } else {
280
-                    // While still running report no error, waiting for resque job to eventually finish
281
-                    // some time in the future
282
-                    $this->log("{$this->Title} is still in progress");
283
-                    return false;
284
-                }
285
-        }
286
-    }
254
+	/**
255
+	 * Check the status of a resque sub-task
256
+	 *
257
+	 * @param string $status Resque task status
258
+	 * @return boolean True if the task is finished successfully
259
+	 */
260
+	protected function checkResqueStatus($status)
261
+	{
262
+		switch ($status) {
263
+			case "Complete":
264
+				return true;
265
+			case "Failed":
266
+			case "Invalid":
267
+				$this->log("{$this->Title} failed with task status $status");
268
+				$this->markFailed();
269
+				return false;
270
+			case "Queued":
271
+			case "Running":
272
+			default:
273
+				// For running or queued tasks ensure that we have not exceeded
274
+				// a reasonable time-elapsed to consider this job inactive
275
+				if ($this->isTimedOut()) {
276
+					$this->log("{$this->Title} took longer than {$this->MaxDuration} seconds to run and has timed out");
277
+					$this->markFailed();
278
+					return false;
279
+				} else {
280
+					// While still running report no error, waiting for resque job to eventually finish
281
+					// some time in the future
282
+					$this->log("{$this->Title} is still in progress");
283
+					return false;
284
+				}
285
+		}
286
+	}
287 287
 }
Please login to merge, or discard this patch.
code/model/steps/SmokeTestPipelineStep.php 1 patch
Indentation   +202 added lines, -202 removed lines patch added patch discarded remove patch
@@ -47,206 +47,206 @@
 block discarded – undo
47 47
 class SmokeTestPipelineStep extends PipelineStep
48 48
 {
49 49
 
50
-    /**
51
-     * Default config setting
52
-     *
53
-     * @var array
54
-     * @config
55
-     */
56
-    private static $default_config = array(
57
-        'RequestTimeout' => 20, // Seconds to allow for each request
58
-        'Attempts' => 1, // Number of attempts allowed
59
-        'AttemptDelay' => 10 // Timeout between requests
60
-    );
61
-
62
-    /**
63
-     * Get all tests to be run by this smoketest
64
-     *
65
-     * @return array List of tests
66
-     */
67
-    protected function getTests()
68
-    {
69
-        // Get core tests
70
-        $tests = $this->getConfigSetting('Tests');
71
-
72
-        // Merge with default tests
73
-        $defaultTests = $this->Pipeline()->getConfigSetting('PipelineConfig', 'Tests');
74
-        if ($tests && $defaultTests) {
75
-            Config::merge_array_low_into_high($tests, $defaultTests);
76
-        } elseif (!$tests && $defaultTests) {
77
-            $tests = $defaultTests;
78
-        }
79
-        if ($tests) {
80
-            return $tests;
81
-        }
82
-
83
-        // if there's no tests to check for, fallback to trying to find the
84
-        // site's homepage by looking at the DNEnvironment fields.
85
-        $environment = $this->getDependentEnvironment();
86
-        $url = $environment->URL;
87
-        if ($url) {
88
-            return array(
89
-                'default' => array(
90
-                    'URL' => $url,
91
-                    'ExpectStatus' => 200
92
-                )
93
-            );
94
-        }
95
-    }
96
-
97
-    /**
98
-     * Initialiase curl handle
99
-     *
100
-     * @return resource Curl handle
101
-     */
102
-    protected function initCurl()
103
-    {
104
-        $handle = curl_init();
105
-
106
-        // avoid curl_exec pushing out the response to the screen
107
-        $timeout = $this->getConfigSetting('RequestTimeout');
108
-        curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
109
-        curl_setopt($handle, CURLOPT_TIMEOUT, $timeout);
110
-        // don't allow this to run for more than 10 seconds to avoid tying up webserver processes.
111
-
112
-        // if we need to use a proxy, ensure that is configured
113
-        if (defined('SS_OUTBOUND_PROXY')) {
114
-            curl_setopt($handle, CURLOPT_PROXY, SS_OUTBOUND_PROXY);
115
-            curl_setopt($handle, CURLOPT_PROXYPORT, SS_OUTBOUND_PROXY_PORT);
116
-        }
117
-        return $handle;
118
-    }
119
-
120
-    /**
121
-     * Run a single test
122
-     *
123
-     * @param resource $ch Curl resource
124
-     * @param string $name Test name
125
-     * @param array $test Test data
126
-     * @return bool success
127
-     */
128
-    public function runTest($ch, $name, $test)
129
-    {
130
-        $this->log(sprintf('Starting smoke test "%s" to URL %s', $name, $test['URL']));
131
-        curl_setopt($ch, CURLOPT_URL, $test['URL']);
132
-
133
-        // Allow individual tests to override number of attempts
134
-        $attempts = (int) $this->getConfigSetting('Attempts');
135
-        if (!empty($test['Attempts'])) {
136
-            $attempts = $test['Attempts'];
137
-        }
138
-
139
-        // Run through each attempt
140
-        for ($i = 0; $i < $attempts; $i++) {
141
-            if ($i > 0) {
142
-                $this->log("Request failed, performing reattempt (#{$i})");
143
-
144
-                // Ensure a non-zero delay between each request
145
-                $delay = $this->getConfigSetting('AttemptDelay');
146
-                sleep($delay);
147
-            }
148
-
149
-            // Perform request
150
-            $contents = curl_exec($ch);
151
-            if (curl_errno($ch)) {
152
-                $this->log(sprintf('Curl error: %s', curl_error($ch)));
153
-                continue;
154
-            }
155
-
156
-            // Check response
157
-            $info = curl_getinfo($ch);
158
-
159
-            // if an expected response time is specified, check that against the results
160
-            if (isset($test['ExpectResponse'])) {
161
-                if ($info['total_time'] > $test['ExpectResponse']) {
162
-                    $this->log(sprintf(
163
-                        'Smoke test "%s" to URL %s failed. Expected response time %s seconds, actual was %s seconds',
164
-                        $name,
165
-                        $test['URL'],
166
-                        $test['ExpectResponse'],
167
-                        $info['total_time']
168
-                    ));
169
-                    continue;
170
-                }
171
-            }
172
-
173
-            // Check response code
174
-            if ($info['http_code'] != $test['ExpectStatus']) {
175
-                $this->log("=================================================================");
176
-                $this->log(sprintf(
177
-                    "Printing output from smoke test '%s' (URL: '%s'):",
178
-                    $name,
179
-                    $test['URL']
180
-                ));
181
-                $this->log(sprintf("HTTP Status Code: %d", $info['http_code']));
182
-                $this->log($contents ? $contents : "No output (check status code?)");
183
-                $this->log("=================================================================");
184
-
185
-                $this->log(sprintf(
186
-                    'Smoke test "%s" to URL %s failed. Expected status code %s, got %s. See above for HTML returned.',
187
-                    $name,
188
-                    $test['URL'],
189
-                    $test['ExpectStatus'],
190
-                    $info['http_code']
191
-                ));
192
-                continue;
193
-            }
194
-
195
-            $this->log(sprintf('Smoke test "%s" to URL %s successful', $name, $test['URL']));
196
-            return true;
197
-        }
198
-
199
-        // Run out of re-attempts
200
-        if ($attempts > 1) {
201
-            $this->log("Failed after {$attempts} attempts");
202
-        }
203
-        return false;
204
-    }
205
-
206
-    public function start()
207
-    {
208
-        $this->Status = 'Started';
209
-        $this->log("Starting {$this->Title}...");
210
-        $this->write();
211
-
212
-        // Get tests to run
213
-        $tests = $this->getTests();
214
-        if (empty($tests)) {
215
-            $this->log('No smoke tests available. Aborting');
216
-            $this->markFailed();
217
-            return false;
218
-        }
219
-
220
-        // work through each of the configured tests and perform a web request and check the result
221
-        $ch = $this->initCurl();
222
-        $success = true;
223
-        foreach ($tests as $name => $test) {
224
-            $testSuccess = $this->runTest($ch, $name, $test);
225
-            $success = $testSuccess && $success;
226
-        }
227
-        curl_close($ch);
228
-
229
-        // Check result
230
-        if ($success) {
231
-            $this->finish();
232
-        } else {
233
-            // At least one test failed, so mark the test as failed
234
-            $this->markFailed();
235
-        }
236
-        return $success;
237
-    }
238
-
239
-    public function markFailed($notify = true)
240
-    {
241
-        if ($this->getDryRun()) {
242
-            $this->log("[Skipped] Smoke testing failed: Putting up emergency maintenance page");
243
-        } else {
244
-            // Put up maintenance page after this fails
245
-            $this->log("Smoke testing failed: Putting up emergency maintenance page");
246
-            $this->Pipeline()->Environment()->enableMaintenace($this->Pipeline()->getLogger());
247
-        }
248
-
249
-        // Mark pipeline and step failed
250
-        parent::markFailed($notify);
251
-    }
50
+	/**
51
+	 * Default config setting
52
+	 *
53
+	 * @var array
54
+	 * @config
55
+	 */
56
+	private static $default_config = array(
57
+		'RequestTimeout' => 20, // Seconds to allow for each request
58
+		'Attempts' => 1, // Number of attempts allowed
59
+		'AttemptDelay' => 10 // Timeout between requests
60
+	);
61
+
62
+	/**
63
+	 * Get all tests to be run by this smoketest
64
+	 *
65
+	 * @return array List of tests
66
+	 */
67
+	protected function getTests()
68
+	{
69
+		// Get core tests
70
+		$tests = $this->getConfigSetting('Tests');
71
+
72
+		// Merge with default tests
73
+		$defaultTests = $this->Pipeline()->getConfigSetting('PipelineConfig', 'Tests');
74
+		if ($tests && $defaultTests) {
75
+			Config::merge_array_low_into_high($tests, $defaultTests);
76
+		} elseif (!$tests && $defaultTests) {
77
+			$tests = $defaultTests;
78
+		}
79
+		if ($tests) {
80
+			return $tests;
81
+		}
82
+
83
+		// if there's no tests to check for, fallback to trying to find the
84
+		// site's homepage by looking at the DNEnvironment fields.
85
+		$environment = $this->getDependentEnvironment();
86
+		$url = $environment->URL;
87
+		if ($url) {
88
+			return array(
89
+				'default' => array(
90
+					'URL' => $url,
91
+					'ExpectStatus' => 200
92
+				)
93
+			);
94
+		}
95
+	}
96
+
97
+	/**
98
+	 * Initialiase curl handle
99
+	 *
100
+	 * @return resource Curl handle
101
+	 */
102
+	protected function initCurl()
103
+	{
104
+		$handle = curl_init();
105
+
106
+		// avoid curl_exec pushing out the response to the screen
107
+		$timeout = $this->getConfigSetting('RequestTimeout');
108
+		curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
109
+		curl_setopt($handle, CURLOPT_TIMEOUT, $timeout);
110
+		// don't allow this to run for more than 10 seconds to avoid tying up webserver processes.
111
+
112
+		// if we need to use a proxy, ensure that is configured
113
+		if (defined('SS_OUTBOUND_PROXY')) {
114
+			curl_setopt($handle, CURLOPT_PROXY, SS_OUTBOUND_PROXY);
115
+			curl_setopt($handle, CURLOPT_PROXYPORT, SS_OUTBOUND_PROXY_PORT);
116
+		}
117
+		return $handle;
118
+	}
119
+
120
+	/**
121
+	 * Run a single test
122
+	 *
123
+	 * @param resource $ch Curl resource
124
+	 * @param string $name Test name
125
+	 * @param array $test Test data
126
+	 * @return bool success
127
+	 */
128
+	public function runTest($ch, $name, $test)
129
+	{
130
+		$this->log(sprintf('Starting smoke test "%s" to URL %s', $name, $test['URL']));
131
+		curl_setopt($ch, CURLOPT_URL, $test['URL']);
132
+
133
+		// Allow individual tests to override number of attempts
134
+		$attempts = (int) $this->getConfigSetting('Attempts');
135
+		if (!empty($test['Attempts'])) {
136
+			$attempts = $test['Attempts'];
137
+		}
138
+
139
+		// Run through each attempt
140
+		for ($i = 0; $i < $attempts; $i++) {
141
+			if ($i > 0) {
142
+				$this->log("Request failed, performing reattempt (#{$i})");
143
+
144
+				// Ensure a non-zero delay between each request
145
+				$delay = $this->getConfigSetting('AttemptDelay');
146
+				sleep($delay);
147
+			}
148
+
149
+			// Perform request
150
+			$contents = curl_exec($ch);
151
+			if (curl_errno($ch)) {
152
+				$this->log(sprintf('Curl error: %s', curl_error($ch)));
153
+				continue;
154
+			}
155
+
156
+			// Check response
157
+			$info = curl_getinfo($ch);
158
+
159
+			// if an expected response time is specified, check that against the results
160
+			if (isset($test['ExpectResponse'])) {
161
+				if ($info['total_time'] > $test['ExpectResponse']) {
162
+					$this->log(sprintf(
163
+						'Smoke test "%s" to URL %s failed. Expected response time %s seconds, actual was %s seconds',
164
+						$name,
165
+						$test['URL'],
166
+						$test['ExpectResponse'],
167
+						$info['total_time']
168
+					));
169
+					continue;
170
+				}
171
+			}
172
+
173
+			// Check response code
174
+			if ($info['http_code'] != $test['ExpectStatus']) {
175
+				$this->log("=================================================================");
176
+				$this->log(sprintf(
177
+					"Printing output from smoke test '%s' (URL: '%s'):",
178
+					$name,
179
+					$test['URL']
180
+				));
181
+				$this->log(sprintf("HTTP Status Code: %d", $info['http_code']));
182
+				$this->log($contents ? $contents : "No output (check status code?)");
183
+				$this->log("=================================================================");
184
+
185
+				$this->log(sprintf(
186
+					'Smoke test "%s" to URL %s failed. Expected status code %s, got %s. See above for HTML returned.',
187
+					$name,
188
+					$test['URL'],
189
+					$test['ExpectStatus'],
190
+					$info['http_code']
191
+				));
192
+				continue;
193
+			}
194
+
195
+			$this->log(sprintf('Smoke test "%s" to URL %s successful', $name, $test['URL']));
196
+			return true;
197
+		}
198
+
199
+		// Run out of re-attempts
200
+		if ($attempts > 1) {
201
+			$this->log("Failed after {$attempts} attempts");
202
+		}
203
+		return false;
204
+	}
205
+
206
+	public function start()
207
+	{
208
+		$this->Status = 'Started';
209
+		$this->log("Starting {$this->Title}...");
210
+		$this->write();
211
+
212
+		// Get tests to run
213
+		$tests = $this->getTests();
214
+		if (empty($tests)) {
215
+			$this->log('No smoke tests available. Aborting');
216
+			$this->markFailed();
217
+			return false;
218
+		}
219
+
220
+		// work through each of the configured tests and perform a web request and check the result
221
+		$ch = $this->initCurl();
222
+		$success = true;
223
+		foreach ($tests as $name => $test) {
224
+			$testSuccess = $this->runTest($ch, $name, $test);
225
+			$success = $testSuccess && $success;
226
+		}
227
+		curl_close($ch);
228
+
229
+		// Check result
230
+		if ($success) {
231
+			$this->finish();
232
+		} else {
233
+			// At least one test failed, so mark the test as failed
234
+			$this->markFailed();
235
+		}
236
+		return $success;
237
+	}
238
+
239
+	public function markFailed($notify = true)
240
+	{
241
+		if ($this->getDryRun()) {
242
+			$this->log("[Skipped] Smoke testing failed: Putting up emergency maintenance page");
243
+		} else {
244
+			// Put up maintenance page after this fails
245
+			$this->log("Smoke testing failed: Putting up emergency maintenance page");
246
+			$this->Pipeline()->Environment()->enableMaintenace($this->Pipeline()->getLogger());
247
+		}
248
+
249
+		// Mark pipeline and step failed
250
+		parent::markFailed($notify);
251
+	}
252 252
 }
Please login to merge, or discard this patch.
code/model/steps/TriggerDeployStep.php 1 patch
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -25,136 +25,136 @@
 block discarded – undo
25 25
 class TriggerDeployStep extends LongRunningPipelineStep
26 26
 {
27 27
 
28
-    /**
29
-     * @var array
30
-     */
31
-    private static $db = array(
32
-        // if this is deployed set the date it was requested
33
-        'Deployed' => "SS_Datetime"
34
-    );
28
+	/**
29
+	 * @var array
30
+	 */
31
+	private static $db = array(
32
+		// if this is deployed set the date it was requested
33
+		'Deployed' => "SS_Datetime"
34
+	);
35 35
 
36
-    /**
37
-     * @var array
38
-     */
39
-    private static $has_one = array(
40
-        'Responder' => 'Member'
41
-    );
36
+	/**
37
+	 * @var array
38
+	 */
39
+	private static $has_one = array(
40
+		'Responder' => 'Member'
41
+	);
42 42
 
43
-    /**
44
-     * @return bool
45
-     */
46
-    public function start()
47
-    {
48
-        // Just in case this step is being mistakenly restarted
49
-        if (!empty($this->Deployed)) {
50
-            $this->log(_t('TriggerDeployStep.BEENDEPLOYED',
51
-                "{$this->Title} has already been deployed"));
52
-            $this->markFailed();
53
-            return false;
54
-        }
43
+	/**
44
+	 * @return bool
45
+	 */
46
+	public function start()
47
+	{
48
+		// Just in case this step is being mistakenly restarted
49
+		if (!empty($this->Deployed)) {
50
+			$this->log(_t('TriggerDeployStep.BEENDEPLOYED',
51
+				"{$this->Title} has already been deployed"));
52
+			$this->markFailed();
53
+			return false;
54
+		}
55 55
 
56
-        // check if we have timed out
57
-        if ($this->isTimedOut()) {
58
-            $this->log(sprintf(_t('TriggerDeployStep.DEPLOYTIMEOUT',
59
-                'Deployment step is older then %s seconds and has timed out'),
60
-                $this->MaxDuration));
61
-            $this->markFailed();
62
-            return false;
63
-        }
56
+		// check if we have timed out
57
+		if ($this->isTimedOut()) {
58
+			$this->log(sprintf(_t('TriggerDeployStep.DEPLOYTIMEOUT',
59
+				'Deployment step is older then %s seconds and has timed out'),
60
+				$this->MaxDuration));
61
+			$this->markFailed();
62
+			return false;
63
+		}
64 64
 
65
-        // Begin or process this step
66
-        switch ($this->Status) {
67
-            case 'Started':
68
-                return true;
69
-            case 'Queued':
70
-                return $this->StartDeployment();
71
-            default:
72
-                $this->log(_t('TriggerDeployStep.STARTERROR',
73
-                     "Unable to process {$this->Title} with status of {$this->Status}"));
74
-                $this->markFailed();
75
-                return false;
76
-        }
77
-    }
65
+		// Begin or process this step
66
+		switch ($this->Status) {
67
+			case 'Started':
68
+				return true;
69
+			case 'Queued':
70
+				return $this->StartDeployment();
71
+			default:
72
+				$this->log(_t('TriggerDeployStep.STARTERROR',
73
+					 "Unable to process {$this->Title} with status of {$this->Status}"));
74
+				$this->markFailed();
75
+				return false;
76
+		}
77
+	}
78 78
 
79
-    /**
80
-     * Can the current user trigger the deployment for this pipeline?
81
-     *
82
-     * @param Member|null $member
83
-     * @return boolean
84
-     */
85
-    public function canTriggerDeploy($member = null)
86
-    {
87
-        return $this->Pipeline()->Environment()->canDeploy($member);
88
-    }
79
+	/**
80
+	 * Can the current user trigger the deployment for this pipeline?
81
+	 *
82
+	 * @param Member|null $member
83
+	 * @return boolean
84
+	 */
85
+	public function canTriggerDeploy($member = null)
86
+	{
87
+		return $this->Pipeline()->Environment()->canDeploy($member);
88
+	}
89 89
 
90
-    /**
91
-     * When a member wishes to deploy this pipeline
92
-     *
93
-     * @return boolean True if successful
94
-     */
95
-    public function deploy()
96
-    {
97
-        // Check permission
98
-        if (!$this->canTriggerDeploy()) {
99
-            return Security::permissionFailure(
100
-                null,
101
-                _t("TriggerDeployStep.DENYTRIGGERDEPLOY",
102
-                "You do not have permission to deploy this pipeline")
103
-            );
104
-        }
90
+	/**
91
+	 * When a member wishes to deploy this pipeline
92
+	 *
93
+	 * @return boolean True if successful
94
+	 */
95
+	public function deploy()
96
+	{
97
+		// Check permission
98
+		if (!$this->canTriggerDeploy()) {
99
+			return Security::permissionFailure(
100
+				null,
101
+				_t("TriggerDeployStep.DENYTRIGGERDEPLOY",
102
+				"You do not have permission to deploy this pipeline")
103
+			);
104
+		}
105 105
 
106
-        if ($this->Status == 'Queued') {
107
-            $this->start();
108
-        }
109
-        // Trigger deployment
110
-        $this->Deployed = SS_Datetime::now()->Rfc2822();
111
-        $this->log(_t('TriggerDeployStep.BEINGDEPLOYED',
112
-            "{$this->Title} is being deployed"));
113
-        $this->ResponderID = Member::currentUserID();
114
-        $this->finish();
115
-        return true;
116
-    }
106
+		if ($this->Status == 'Queued') {
107
+			$this->start();
108
+		}
109
+		// Trigger deployment
110
+		$this->Deployed = SS_Datetime::now()->Rfc2822();
111
+		$this->log(_t('TriggerDeployStep.BEINGDEPLOYED',
112
+			"{$this->Title} is being deployed"));
113
+		$this->ResponderID = Member::currentUserID();
114
+		$this->finish();
115
+		return true;
116
+	}
117 117
 
118
-    /**
119
-     * Initiate the deployment process
120
-     */
121
-    public function StartDeployment()
122
-    {
123
-        $this->Status = 'Started';
124
-        if (!$this->Started) {
125
-            $this->Started = SS_Datetime::now()->Rfc2822();
126
-        }
127
-        $this->log("Starting {$this->Title}...");
128
-        $this->write();
129
-        return true;
130
-    }
118
+	/**
119
+	 * Initiate the deployment process
120
+	 */
121
+	public function StartDeployment()
122
+	{
123
+		$this->Status = 'Started';
124
+		if (!$this->Started) {
125
+			$this->Started = SS_Datetime::now()->Rfc2822();
126
+		}
127
+		$this->log("Starting {$this->Title}...");
128
+		$this->write();
129
+		return true;
130
+	}
131 131
 
132
-    public function getRunningDescription()
133
-    {
134
-        // Don't show options if this step has already been confirmed
135
-        if ($this->Deployed) {
136
-            return;
137
-        }
132
+	public function getRunningDescription()
133
+	{
134
+		// Don't show options if this step has already been confirmed
135
+		if ($this->Deployed) {
136
+			return;
137
+		}
138 138
 
139
-        return _t('TriggerDeployStep.RUNNINGDESCRIPTION',
140
-            'Please press the "Deploy" button to continue deployment');
141
-    }
139
+		return _t('TriggerDeployStep.RUNNINGDESCRIPTION',
140
+			'Please press the "Deploy" button to continue deployment');
141
+	}
142 142
 
143
-    public function allowedActions()
144
-    {
145
-        // Don't show options if this step has already been confirmed or can't be confirmed
146
-        if (!$this->canTriggerDeploy()) {
147
-            return parent::allowedActions();
148
-        }
143
+	public function allowedActions()
144
+	{
145
+		// Don't show options if this step has already been confirmed or can't be confirmed
146
+		if (!$this->canTriggerDeploy()) {
147
+			return parent::allowedActions();
148
+		}
149 149
 
150
-        // Return actions
151
-        return array(
152
-            'deploy' => array(
153
-                'ButtonText' => 'Deploy',
154
-                'ButtonType' => 'btn-success',
155
-                'Link' => $this->Pipeline()->StepLink('deploy'),
156
-                'Title' => 'Trigger the current deployment, allowing it to continue'
157
-            )
158
-        );
159
-    }
150
+		// Return actions
151
+		return array(
152
+			'deploy' => array(
153
+				'ButtonText' => 'Deploy',
154
+				'ButtonType' => 'btn-success',
155
+				'Link' => $this->Pipeline()->StepLink('deploy'),
156
+				'Title' => 'Trigger the current deployment, allowing it to continue'
157
+			)
158
+		);
159
+	}
160 160
 }
Please login to merge, or discard this patch.
code/model/steps/UserConfirmationStep.php 1 patch
Indentation   +368 added lines, -368 removed lines patch added patch discarded remove patch
@@ -55,372 +55,372 @@
 block discarded – undo
55 55
 class UserConfirmationStep extends LongRunningPipelineStep
56 56
 {
57 57
 
58
-    /**
59
-     * Messages
60
-     */
61
-    const ALERT_APPROVE = 'Approve';
62
-    const ALERT_TIMEOUT = 'TimeOut';
63
-    const ALERT_REQUEST = 'Request';
64
-    const ALERT_REJECT = 'Reject';
65
-
66
-    /**
67
-     * Message roles
68
-     */
69
-    const ROLE_REQUESTER = 'Requester';
70
-    const ROLE_RECIPIENT = 'Recipient';
71
-
72
-    /**
73
-     * @var array
74
-     */
75
-    private static $db = array(
76
-        // A finished step is approved and a failed step is rejected.
77
-        // Aborted confirmation is left as None
78
-        'Approval' => "Enum('Approved,Rejected,None', 'None')",
79
-        // If RecipientsDelay is specified, this value records the index of the most recently notified
80
-        // group of users. This will be incremented once another level of fallback has been notified.
81
-        // E.g. once primary admin has been notified, the secondary admin can be notified, and this
82
-        // is incremented
83
-        'NotifiedGroup' => 'Int'
84
-    );
85
-
86
-    /**
87
-     * @var array
88
-     */
89
-    private static $defaults = array(
90
-        'Approval' => 'None',
91
-        'NotifiedGroup' => 0
92
-    );
93
-
94
-    /**
95
-     * @var array
96
-     */
97
-    private static $has_one = array(
98
-        'Responder' => 'Member'
99
-    );
100
-
101
-    /**
102
-     * This step depends on a configured messaging service
103
-     *
104
-     * @config
105
-     * @var array
106
-     */
107
-    private static $dependencies = array(
108
-        'MessagingService' => '%$ConfirmationMessagingService'
109
-    );
110
-
111
-    /**
112
-     * Currently assigned messaging service
113
-     *
114
-     * @var ConfirmationMessagingService
115
-     */
116
-    private $messagingService = null;
117
-
118
-    /**
119
-     * Assign a messaging service for this step
120
-     *
121
-     * @param ConfirmationMessagingService $service
122
-     */
123
-    public function setMessagingService(ConfirmationMessagingService $service)
124
-    {
125
-        $this->messagingService = $service;
126
-    }
127
-
128
-    /**
129
-     * Get the currently configured messaging service
130
-     *
131
-     * @return ConfirmationMessagingService
132
-     */
133
-    public function getMessagingService()
134
-    {
135
-        return $this->messagingService;
136
-    }
137
-
138
-    /**
139
-     * Determine if the confirmation has been responded to (ether with acceptance, rejection, or cancelled)
140
-     *
141
-     * @return boolean
142
-     */
143
-    public function hasResponse()
144
-    {
145
-        return $this->Approval !== 'None';
146
-    }
147
-
148
-    public function start()
149
-    {
150
-        parent::start();
151
-
152
-        // Just in case this step is being mistakenly restarted
153
-        if ($this->hasResponse()) {
154
-            $this->log("{$this->Title} has already been processed with a response of {$this->Approval}");
155
-            $this->markFailed();
156
-            return false;
157
-        }
158
-
159
-        // Begin or process this step
160
-        switch ($this->Status) {
161
-            case 'Started':
162
-                return $this->checkStatus();
163
-            case 'Queued':
164
-                return $this->startApproval();
165
-            default:
166
-                $this->log("Unable to process {$this->Title} with status of {$this->Status}");
167
-                $this->markFailed();
168
-                return false;
169
-        }
170
-    }
171
-
172
-    /**
173
-     * Can the current user approve this pipeline?
174
-     *
175
-     * @param Member|null $member
176
-     * @return boolean
177
-     */
178
-    public function canApprove($member = null)
179
-    {
180
-        return $this->Pipeline()->Environment()->canApprove($member);
181
-    }
182
-
183
-    /**
184
-     * When the recipient wishes to approve this request
185
-     *
186
-     * @return boolean True if successful
187
-     */
188
-    public function approve()
189
-    {
190
-        // Check permission
191
-        if (!$this->canApprove()) {
192
-            return Security::permissionFailure(
193
-                null,
194
-                _t("UserConfirmationStep.DENYAPPROVE", "You do not have permission to approve this deployment")
195
-            );
196
-        }
197
-
198
-        // Skip subsequent approvals if already approved / rejected
199
-        if ($this->hasResponse()) {
200
-            return;
201
-        }
202
-
203
-        // Approve
204
-        $this->Approval = 'Approved';
205
-        $this->log("{$this->Title} has been approved");
206
-        $this->ResponderID = Member::currentUserID();
207
-        $this->finish();
208
-        $this->sendMessage(self::ALERT_APPROVE);
209
-        return true;
210
-    }
211
-
212
-    /**
213
-     * When the recipient wishes to reject this request
214
-     *
215
-     * @return boolean True if successful
216
-     */
217
-    public function reject()
218
-    {
219
-        // Check permission
220
-        if (!$this->canApprove()) {
221
-            return Security::permissionFailure(
222
-                null,
223
-                _t("UserConfirmationStep.DENYREJECT", "You do not have permission to reject this deployment")
224
-            );
225
-        }
226
-
227
-        // Skip subsequent approvals if already approved / rejected
228
-        if ($this->hasResponse()) {
229
-            return;
230
-        }
231
-
232
-        // Reject
233
-        $this->Approval = 'Rejected';
234
-        $this->log("{$this->Title} has been rejected");
235
-        $this->ResponderID = Member::currentUserID();
236
-        $this->markFailed(false);
237
-        $this->sendMessage(self::ALERT_REJECT);
238
-        return true;
239
-    }
240
-
241
-    /**
242
-     * Report the status of the current request queue and makes sure it hasn't overrun it's time allowed
243
-     *
244
-     * @return boolean True if not failed
245
-     */
246
-    protected function checkStatus()
247
-    {
248
-        // For running or queued tasks ensure that we have not exceeded
249
-        // a reasonable time-elapsed to consider this job inactive
250
-        if ($this->isTimedOut()) {
251
-            $days = round($this->MaxDuration / (24.0 * 3600.0), 1);
252
-            $logMessage = "{$this->Title} took longer than {$this->MaxDuration} seconds ($days days) to be approved "
253
-                . "and has timed out";
254
-            $this->log($logMessage);
255
-            $this->markFailed();
256
-            $this->sendMessage(self::ALERT_TIMEOUT);
257
-            return false;
258
-        }
259
-
260
-        // If operating on a delayed notification schedule, determine if there are further groups who should be notified
261
-        if ($delay = $this->getConfigSetting('RecipientsDelay')) {
262
-            // Check group that should have been notified by now
263
-            $age = $this->getAge();
264
-            $escallateGroup = intval($age / $delay);
265
-            $recipients = $this->getConfigSetting('Recipients');
266
-            $lastGroup = count($recipients) - 1;
267
-            // If we can notify the next group, do so
268
-            // We only escallate one group at a time to ensure correct order is followed
269
-            if ($this->NotifiedGroup < $lastGroup && $this->NotifiedGroup < $escallateGroup) {
270
-                $this->NotifiedGroup++;
271
-                $groupDescription = is_array($recipients[$this->NotifiedGroup])
272
-                    ? implode(',', $recipients[$this->NotifiedGroup])
273
-                    : $recipients[$this->NotifiedGroup];
274
-                $this->log("Escalating approval request to group {$this->NotifiedGroup}: '$groupDescription'");
275
-                // Send to selected group
276
-                $this->sendMessage(self::ALERT_REQUEST, $this->NotifiedGroup);
277
-                $this->write();
278
-                return true;
279
-            }
280
-        }
281
-
282
-
283
-        // While still running report no error, waiting for resque job to eventually finish.
284
-        // Since this could potentially fill the log with hundreds of thousands of messages,
285
-        // if it takes a few days to get a response, don't write anything.
286
-        return true;
287
-    }
288
-
289
-    /**
290
-     * Initiate the approval process
291
-     */
292
-    public function startApproval()
293
-    {
294
-        $this->Status = 'Started';
295
-        $this->log("Starting {$this->Title}...");
296
-        // Determine if we should use delayed notification
297
-        $recipientGroup = 'all';
298
-        if ($this->getConfigSetting('RecipientsDelay')) {
299
-            $this->NotifiedGroup = $recipientGroup = 0;
300
-        }
301
-        // Send to selected group
302
-        $this->sendMessage(self::ALERT_REQUEST, $recipientGroup);
303
-        $this->write();
304
-        return true;
305
-    }
306
-
307
-    /**
308
-     * Finds a message template for a given role and message
309
-     *
310
-     * @param string $role Role name for role-customised messages. Usually 'Requester' or 'Recipient'
311
-     * @param string $messageID Message ID
312
-     * @return array Resulting array(subject, message)
313
-     */
314
-    protected function generateMessageTemplate($role, $messageID)
315
-    {
316
-        $subject = $this->getConfigSetting('Subjects', "$messageID-$role")
317
-                ?: $this->getConfigSetting('Subjects', $messageID);
318
-        $message = $this->getConfigSetting('Messages', "$messageID-$role")
319
-                ?: $this->getConfigSetting('Messages', $messageID);
320
-        $substitutions = $this->getReplacements();
321
-        return $this
322
-            ->Pipeline()
323
-            ->injectMessageReplacements($message, $subject, $substitutions);
324
-    }
325
-
326
-    /**
327
-     * Retrieve message replacements
328
-     *
329
-     * @return array
330
-     */
331
-    public function getReplacements()
332
-    {
333
-        // Get member who began this request
334
-        return array_merge(
335
-            $this->Pipeline()->getReplacements(),
336
-            array(
337
-                // Note that this actually displays the link to the interface to approve,
338
-                // not the direct link to the approve action
339
-                '<approvelink>' => Director::absoluteURL($this->Pipeline()->Environment()->Link())
340
-            )
341
-        );
342
-    }
343
-
344
-    /**
345
-     * Sends a message to a specified recipient(s)
346
-     *
347
-     * @param string $messageID Message ID. One of 'Reject', 'Approve', 'TimeOut' or 'Request'
348
-     * @param mixed $recipientGroup Either a numeric index of the next recipient to send to, or "all" for all
349
-     * This is used for delayed notification so that failover recipients can be notified.
350
-     * @return boolean|null True if successful
351
-     */
352
-    protected function sendMessage($messageID, $recipientGroup = 'all')
353
-    {
354
-        // Add additionally configured arguments
355
-        $arguments = $this->getConfigSetting('ServiceArguments') ?: array();
356
-
357
-        // Get member who began this request
358
-        $author = $this->Pipeline()->Author();
359
-
360
-        // Send message to requester
361
-        if ($recipientGroup === 'all' || $recipientGroup === 0) {
362
-            list($subject, $message) = $this->generateMessageTemplate(self::ROLE_REQUESTER, $messageID);
363
-            if ($subject && $message) {
364
-                $this->log("{$this->Title} sending $messageID message to {$author->Email}");
365
-                $extra = array('subject' => $subject);
366
-                $this->messagingService->sendMessage($this, $message, $author, array_merge($arguments, $extra));
367
-            }
368
-        }
369
-
370
-        // Filter recipients based on group
371
-        $recipients = $this->getConfigSetting('Recipients');
372
-        if (is_array($recipients) && $recipientGroup !== 'all') {
373
-            $recipients = isset($recipients[$recipientGroup])
374
-                ? $recipients[$recipientGroup]
375
-                : null;
376
-        }
377
-        if (empty($recipients)) {
378
-            $this->log("Skipping sending message to empty recipients");
379
-            return;
380
-        }
381
-
382
-        // Send to recipients
383
-        list($subject, $message) = $this->generateMessageTemplate(self::ROLE_RECIPIENT, $messageID);
384
-        if ($subject && $message && $recipients) {
385
-            $recipientsStr = is_array($recipients) ? implode(',', $recipients) : $recipients;
386
-            $this->log("{$this->Title} sending $messageID message to $recipientsStr");
387
-            $extra = array('subject' => $subject);
388
-            $this->messagingService->sendMessage($this, $message, $recipients, array_merge($arguments, $extra));
389
-        }
390
-    }
391
-
392
-    public function getRunningDescription()
393
-    {
394
-
395
-        // Don't show options if this step has already been confirmed
396
-        if ($this->hasResponse() || !$this->isRunning()) {
397
-            return;
398
-        }
399
-
400
-        return 'This deployment is currently awaiting approval before it can complete.';
401
-    }
402
-
403
-    public function allowedActions()
404
-    {
405
-        // Don't show options if this step has already been confirmed or can't be confirmed
406
-        if ($this->hasResponse() || !$this->isRunning() || !$this->canApprove()) {
407
-            return parent::allowedActions();
408
-        }
409
-
410
-        // Return actions
411
-        return array(
412
-            'approve' => array(
413
-                'ButtonText' => 'Approve',
414
-                'ButtonType' => 'btn-success',
415
-                'Link' => $this->Pipeline()->StepLink('approve'),
416
-                'Title' => 'Approves the current deployment, allowing it to continue'
417
-            ),
418
-            'reject' => array(
419
-                'ButtonText' => 'Reject',
420
-                'ButtonType' => 'btn-danger',
421
-                'Link' => $this->Pipeline()->StepLink('reject'),
422
-                'Title' => 'Deny the request to release this deployment'
423
-            )
424
-        );
425
-    }
58
+	/**
59
+	 * Messages
60
+	 */
61
+	const ALERT_APPROVE = 'Approve';
62
+	const ALERT_TIMEOUT = 'TimeOut';
63
+	const ALERT_REQUEST = 'Request';
64
+	const ALERT_REJECT = 'Reject';
65
+
66
+	/**
67
+	 * Message roles
68
+	 */
69
+	const ROLE_REQUESTER = 'Requester';
70
+	const ROLE_RECIPIENT = 'Recipient';
71
+
72
+	/**
73
+	 * @var array
74
+	 */
75
+	private static $db = array(
76
+		// A finished step is approved and a failed step is rejected.
77
+		// Aborted confirmation is left as None
78
+		'Approval' => "Enum('Approved,Rejected,None', 'None')",
79
+		// If RecipientsDelay is specified, this value records the index of the most recently notified
80
+		// group of users. This will be incremented once another level of fallback has been notified.
81
+		// E.g. once primary admin has been notified, the secondary admin can be notified, and this
82
+		// is incremented
83
+		'NotifiedGroup' => 'Int'
84
+	);
85
+
86
+	/**
87
+	 * @var array
88
+	 */
89
+	private static $defaults = array(
90
+		'Approval' => 'None',
91
+		'NotifiedGroup' => 0
92
+	);
93
+
94
+	/**
95
+	 * @var array
96
+	 */
97
+	private static $has_one = array(
98
+		'Responder' => 'Member'
99
+	);
100
+
101
+	/**
102
+	 * This step depends on a configured messaging service
103
+	 *
104
+	 * @config
105
+	 * @var array
106
+	 */
107
+	private static $dependencies = array(
108
+		'MessagingService' => '%$ConfirmationMessagingService'
109
+	);
110
+
111
+	/**
112
+	 * Currently assigned messaging service
113
+	 *
114
+	 * @var ConfirmationMessagingService
115
+	 */
116
+	private $messagingService = null;
117
+
118
+	/**
119
+	 * Assign a messaging service for this step
120
+	 *
121
+	 * @param ConfirmationMessagingService $service
122
+	 */
123
+	public function setMessagingService(ConfirmationMessagingService $service)
124
+	{
125
+		$this->messagingService = $service;
126
+	}
127
+
128
+	/**
129
+	 * Get the currently configured messaging service
130
+	 *
131
+	 * @return ConfirmationMessagingService
132
+	 */
133
+	public function getMessagingService()
134
+	{
135
+		return $this->messagingService;
136
+	}
137
+
138
+	/**
139
+	 * Determine if the confirmation has been responded to (ether with acceptance, rejection, or cancelled)
140
+	 *
141
+	 * @return boolean
142
+	 */
143
+	public function hasResponse()
144
+	{
145
+		return $this->Approval !== 'None';
146
+	}
147
+
148
+	public function start()
149
+	{
150
+		parent::start();
151
+
152
+		// Just in case this step is being mistakenly restarted
153
+		if ($this->hasResponse()) {
154
+			$this->log("{$this->Title} has already been processed with a response of {$this->Approval}");
155
+			$this->markFailed();
156
+			return false;
157
+		}
158
+
159
+		// Begin or process this step
160
+		switch ($this->Status) {
161
+			case 'Started':
162
+				return $this->checkStatus();
163
+			case 'Queued':
164
+				return $this->startApproval();
165
+			default:
166
+				$this->log("Unable to process {$this->Title} with status of {$this->Status}");
167
+				$this->markFailed();
168
+				return false;
169
+		}
170
+	}
171
+
172
+	/**
173
+	 * Can the current user approve this pipeline?
174
+	 *
175
+	 * @param Member|null $member
176
+	 * @return boolean
177
+	 */
178
+	public function canApprove($member = null)
179
+	{
180
+		return $this->Pipeline()->Environment()->canApprove($member);
181
+	}
182
+
183
+	/**
184
+	 * When the recipient wishes to approve this request
185
+	 *
186
+	 * @return boolean True if successful
187
+	 */
188
+	public function approve()
189
+	{
190
+		// Check permission
191
+		if (!$this->canApprove()) {
192
+			return Security::permissionFailure(
193
+				null,
194
+				_t("UserConfirmationStep.DENYAPPROVE", "You do not have permission to approve this deployment")
195
+			);
196
+		}
197
+
198
+		// Skip subsequent approvals if already approved / rejected
199
+		if ($this->hasResponse()) {
200
+			return;
201
+		}
202
+
203
+		// Approve
204
+		$this->Approval = 'Approved';
205
+		$this->log("{$this->Title} has been approved");
206
+		$this->ResponderID = Member::currentUserID();
207
+		$this->finish();
208
+		$this->sendMessage(self::ALERT_APPROVE);
209
+		return true;
210
+	}
211
+
212
+	/**
213
+	 * When the recipient wishes to reject this request
214
+	 *
215
+	 * @return boolean True if successful
216
+	 */
217
+	public function reject()
218
+	{
219
+		// Check permission
220
+		if (!$this->canApprove()) {
221
+			return Security::permissionFailure(
222
+				null,
223
+				_t("UserConfirmationStep.DENYREJECT", "You do not have permission to reject this deployment")
224
+			);
225
+		}
226
+
227
+		// Skip subsequent approvals if already approved / rejected
228
+		if ($this->hasResponse()) {
229
+			return;
230
+		}
231
+
232
+		// Reject
233
+		$this->Approval = 'Rejected';
234
+		$this->log("{$this->Title} has been rejected");
235
+		$this->ResponderID = Member::currentUserID();
236
+		$this->markFailed(false);
237
+		$this->sendMessage(self::ALERT_REJECT);
238
+		return true;
239
+	}
240
+
241
+	/**
242
+	 * Report the status of the current request queue and makes sure it hasn't overrun it's time allowed
243
+	 *
244
+	 * @return boolean True if not failed
245
+	 */
246
+	protected function checkStatus()
247
+	{
248
+		// For running or queued tasks ensure that we have not exceeded
249
+		// a reasonable time-elapsed to consider this job inactive
250
+		if ($this->isTimedOut()) {
251
+			$days = round($this->MaxDuration / (24.0 * 3600.0), 1);
252
+			$logMessage = "{$this->Title} took longer than {$this->MaxDuration} seconds ($days days) to be approved "
253
+				. "and has timed out";
254
+			$this->log($logMessage);
255
+			$this->markFailed();
256
+			$this->sendMessage(self::ALERT_TIMEOUT);
257
+			return false;
258
+		}
259
+
260
+		// If operating on a delayed notification schedule, determine if there are further groups who should be notified
261
+		if ($delay = $this->getConfigSetting('RecipientsDelay')) {
262
+			// Check group that should have been notified by now
263
+			$age = $this->getAge();
264
+			$escallateGroup = intval($age / $delay);
265
+			$recipients = $this->getConfigSetting('Recipients');
266
+			$lastGroup = count($recipients) - 1;
267
+			// If we can notify the next group, do so
268
+			// We only escallate one group at a time to ensure correct order is followed
269
+			if ($this->NotifiedGroup < $lastGroup && $this->NotifiedGroup < $escallateGroup) {
270
+				$this->NotifiedGroup++;
271
+				$groupDescription = is_array($recipients[$this->NotifiedGroup])
272
+					? implode(',', $recipients[$this->NotifiedGroup])
273
+					: $recipients[$this->NotifiedGroup];
274
+				$this->log("Escalating approval request to group {$this->NotifiedGroup}: '$groupDescription'");
275
+				// Send to selected group
276
+				$this->sendMessage(self::ALERT_REQUEST, $this->NotifiedGroup);
277
+				$this->write();
278
+				return true;
279
+			}
280
+		}
281
+
282
+
283
+		// While still running report no error, waiting for resque job to eventually finish.
284
+		// Since this could potentially fill the log with hundreds of thousands of messages,
285
+		// if it takes a few days to get a response, don't write anything.
286
+		return true;
287
+	}
288
+
289
+	/**
290
+	 * Initiate the approval process
291
+	 */
292
+	public function startApproval()
293
+	{
294
+		$this->Status = 'Started';
295
+		$this->log("Starting {$this->Title}...");
296
+		// Determine if we should use delayed notification
297
+		$recipientGroup = 'all';
298
+		if ($this->getConfigSetting('RecipientsDelay')) {
299
+			$this->NotifiedGroup = $recipientGroup = 0;
300
+		}
301
+		// Send to selected group
302
+		$this->sendMessage(self::ALERT_REQUEST, $recipientGroup);
303
+		$this->write();
304
+		return true;
305
+	}
306
+
307
+	/**
308
+	 * Finds a message template for a given role and message
309
+	 *
310
+	 * @param string $role Role name for role-customised messages. Usually 'Requester' or 'Recipient'
311
+	 * @param string $messageID Message ID
312
+	 * @return array Resulting array(subject, message)
313
+	 */
314
+	protected function generateMessageTemplate($role, $messageID)
315
+	{
316
+		$subject = $this->getConfigSetting('Subjects', "$messageID-$role")
317
+				?: $this->getConfigSetting('Subjects', $messageID);
318
+		$message = $this->getConfigSetting('Messages', "$messageID-$role")
319
+				?: $this->getConfigSetting('Messages', $messageID);
320
+		$substitutions = $this->getReplacements();
321
+		return $this
322
+			->Pipeline()
323
+			->injectMessageReplacements($message, $subject, $substitutions);
324
+	}
325
+
326
+	/**
327
+	 * Retrieve message replacements
328
+	 *
329
+	 * @return array
330
+	 */
331
+	public function getReplacements()
332
+	{
333
+		// Get member who began this request
334
+		return array_merge(
335
+			$this->Pipeline()->getReplacements(),
336
+			array(
337
+				// Note that this actually displays the link to the interface to approve,
338
+				// not the direct link to the approve action
339
+				'<approvelink>' => Director::absoluteURL($this->Pipeline()->Environment()->Link())
340
+			)
341
+		);
342
+	}
343
+
344
+	/**
345
+	 * Sends a message to a specified recipient(s)
346
+	 *
347
+	 * @param string $messageID Message ID. One of 'Reject', 'Approve', 'TimeOut' or 'Request'
348
+	 * @param mixed $recipientGroup Either a numeric index of the next recipient to send to, or "all" for all
349
+	 * This is used for delayed notification so that failover recipients can be notified.
350
+	 * @return boolean|null True if successful
351
+	 */
352
+	protected function sendMessage($messageID, $recipientGroup = 'all')
353
+	{
354
+		// Add additionally configured arguments
355
+		$arguments = $this->getConfigSetting('ServiceArguments') ?: array();
356
+
357
+		// Get member who began this request
358
+		$author = $this->Pipeline()->Author();
359
+
360
+		// Send message to requester
361
+		if ($recipientGroup === 'all' || $recipientGroup === 0) {
362
+			list($subject, $message) = $this->generateMessageTemplate(self::ROLE_REQUESTER, $messageID);
363
+			if ($subject && $message) {
364
+				$this->log("{$this->Title} sending $messageID message to {$author->Email}");
365
+				$extra = array('subject' => $subject);
366
+				$this->messagingService->sendMessage($this, $message, $author, array_merge($arguments, $extra));
367
+			}
368
+		}
369
+
370
+		// Filter recipients based on group
371
+		$recipients = $this->getConfigSetting('Recipients');
372
+		if (is_array($recipients) && $recipientGroup !== 'all') {
373
+			$recipients = isset($recipients[$recipientGroup])
374
+				? $recipients[$recipientGroup]
375
+				: null;
376
+		}
377
+		if (empty($recipients)) {
378
+			$this->log("Skipping sending message to empty recipients");
379
+			return;
380
+		}
381
+
382
+		// Send to recipients
383
+		list($subject, $message) = $this->generateMessageTemplate(self::ROLE_RECIPIENT, $messageID);
384
+		if ($subject && $message && $recipients) {
385
+			$recipientsStr = is_array($recipients) ? implode(',', $recipients) : $recipients;
386
+			$this->log("{$this->Title} sending $messageID message to $recipientsStr");
387
+			$extra = array('subject' => $subject);
388
+			$this->messagingService->sendMessage($this, $message, $recipients, array_merge($arguments, $extra));
389
+		}
390
+	}
391
+
392
+	public function getRunningDescription()
393
+	{
394
+
395
+		// Don't show options if this step has already been confirmed
396
+		if ($this->hasResponse() || !$this->isRunning()) {
397
+			return;
398
+		}
399
+
400
+		return 'This deployment is currently awaiting approval before it can complete.';
401
+	}
402
+
403
+	public function allowedActions()
404
+	{
405
+		// Don't show options if this step has already been confirmed or can't be confirmed
406
+		if ($this->hasResponse() || !$this->isRunning() || !$this->canApprove()) {
407
+			return parent::allowedActions();
408
+		}
409
+
410
+		// Return actions
411
+		return array(
412
+			'approve' => array(
413
+				'ButtonText' => 'Approve',
414
+				'ButtonType' => 'btn-success',
415
+				'Link' => $this->Pipeline()->StepLink('approve'),
416
+				'Title' => 'Approves the current deployment, allowing it to continue'
417
+			),
418
+			'reject' => array(
419
+				'ButtonText' => 'Reject',
420
+				'ButtonType' => 'btn-danger',
421
+				'Link' => $this->Pipeline()->StepLink('reject'),
422
+				'Title' => 'Deny the request to release this deployment'
423
+			)
424
+		);
425
+	}
426 426
 }
Please login to merge, or discard this patch.
code/queuereport/ResqueJob.php 1 patch
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -9,68 +9,68 @@
 block discarded – undo
9 9
 class ResqueJob extends ViewableData
10 10
 {
11 11
 
12
-    /**
13
-     * @var array
14
-     */
15
-    protected $record = array();
12
+	/**
13
+	 * @var array
14
+	 */
15
+	protected $record = array();
16 16
 
17
-    /**
18
-     * @param array $data
19
-     */
20
-    public function __construct($data = array())
21
-    {
22
-        $this->record = $data;
23
-    }
17
+	/**
18
+	 * @param array $data
19
+	 */
20
+	public function __construct($data = array())
21
+	{
22
+		$this->record = $data;
23
+	}
24 24
 
25
-    /**
26
-     * @return string
27
-     */
28
-    public function i18n_singular_name()
29
-    {
30
-        return 'Resque queue';
31
-    }
25
+	/**
26
+	 * @return string
27
+	 */
28
+	public function i18n_singular_name()
29
+	{
30
+		return 'Resque queue';
31
+	}
32 32
 
33
-    /**
34
-     * @return boolean
35
-     */
36
-    public function canView()
37
-    {
38
-        return true;
39
-    }
33
+	/**
34
+	 * @return boolean
35
+	 */
36
+	public function canView()
37
+	{
38
+		return true;
39
+	}
40 40
 
41
-    /**
42
-     * @return bool
43
-     */
44
-    public function canEdit()
45
-    {
46
-        return false;
47
-    }
41
+	/**
42
+	 * @return bool
43
+	 */
44
+	public function canEdit()
45
+	{
46
+		return false;
47
+	}
48 48
 
49
-    /**
50
-     * @return bool
51
-     */
52
-    public function candelete()
53
-    {
54
-        return false;
55
-    }
49
+	/**
50
+	 * @return bool
51
+	 */
52
+	public function candelete()
53
+	{
54
+		return false;
55
+	}
56 56
 
57
-    /**
58
-     * @return bool
59
-     */
60
-    public function cancreate()
61
-    {
62
-        return false;
63
-    }
57
+	/**
58
+	 * @return bool
59
+	 */
60
+	public function cancreate()
61
+	{
62
+		return false;
63
+	}
64 64
 
65
-    /**
66
-     * @param string $property
67
-     * @return mixed
68
-     */
69
-    public function __get($property)
70
-    {
71
-        if (isset($this->record[$property])) {
72
-            return $this->record[$property];
73
-        }
74
-        return null;
75
-    }
65
+	/**
66
+	 * @param string $property
67
+	 * @return mixed
68
+	 */
69
+	public function __get($property)
70
+	{
71
+		if (isset($this->record[$property])) {
72
+			return $this->record[$property];
73
+		}
74
+		return null;
75
+	}
76 76
 }
Please login to merge, or discard this patch.
code/queuereport/ResqueQueue.php 1 patch
Indentation   +104 added lines, -104 removed lines patch added patch discarded remove patch
@@ -11,119 +11,119 @@
 block discarded – undo
11 11
 class ResqueQueue extends ViewableData
12 12
 {
13 13
 
14
-    /**
15
-     * @var array
16
-     */
17
-    protected $record = array();
14
+	/**
15
+	 * @var array
16
+	 */
17
+	protected $record = array();
18 18
 
19
-    /**
20
-     * @param array $data
21
-     */
22
-    public function __construct($data = array())
23
-    {
24
-        $this->record = $data;
25
-    }
19
+	/**
20
+	 * @param array $data
21
+	 */
22
+	public function __construct($data = array())
23
+	{
24
+		$this->record = $data;
25
+	}
26 26
 
27
-    /**
28
-     * @return \FieldList
29
-     */
30
-    public function getCMSFields()
31
-    {
32
-        $fieldList = new FieldList();
33
-        $fieldList->push(new ReadonlyField('Name', 'Name', $this->Name));
34
-        $fieldList->push(new ReadonlyField('Size', 'Size', $this->Size));
35
-        $jobs = new GridField('Jobs', 'Jobs', $this->getJobs());
36
-        $dataComponent = $jobs->getConfig()->getComponentByType('GridFieldDataColumns');
37
-        $dataComponent->setDisplayFields(array(
38
-            'Name' => 'Name',
39
-            'Value' => 'Value',
40
-        ));
41
-        $fieldList->push($jobs);
42
-        return $fieldList;
43
-    }
27
+	/**
28
+	 * @return \FieldList
29
+	 */
30
+	public function getCMSFields()
31
+	{
32
+		$fieldList = new FieldList();
33
+		$fieldList->push(new ReadonlyField('Name', 'Name', $this->Name));
34
+		$fieldList->push(new ReadonlyField('Size', 'Size', $this->Size));
35
+		$jobs = new GridField('Jobs', 'Jobs', $this->getJobs());
36
+		$dataComponent = $jobs->getConfig()->getComponentByType('GridFieldDataColumns');
37
+		$dataComponent->setDisplayFields(array(
38
+			'Name' => 'Name',
39
+			'Value' => 'Value',
40
+		));
41
+		$fieldList->push($jobs);
42
+		return $fieldList;
43
+	}
44 44
 
45
-    /**
46
-     * @return string
47
-     */
48
-    public function i18n_singular_name()
49
-    {
50
-        return 'Resque queue';
51
-    }
45
+	/**
46
+	 * @return string
47
+	 */
48
+	public function i18n_singular_name()
49
+	{
50
+		return 'Resque queue';
51
+	}
52 52
 
53
-    protected function getJobs()
54
-    {
55
-        $jobs = new ArrayList();
53
+	protected function getJobs()
54
+	{
55
+		$jobs = new ArrayList();
56 56
 
57
-        $resqueJobs = Resque::redis()->lrange('queue:' . $this->Name, 0, -1);
58
-        if (!$resqueJobs) {
59
-            $jobs->push(new ResqueJob(array(
60
-                'Name' => 'null',
61
-                'Value' => 'null',
62
-            )));
63
-            return $jobs;
64
-        }
65
-        foreach ($resqueJobs as $idx => $job) {
66
-            $stdClass = json_decode($job);
67
-            if ($stdClass->class === 'CapistranoDeploy' || $stdClass->class === 'DeployJob') {
68
-                $value = $stdClass->args[0]->projectName
69
-                    . ':' . $stdClass->args[0]->environment
70
-                    . ' - ' . $stdClass->args[0]->sha;
71
-                $jobs->push(new ResqueJob(array(
72
-                    'Name' => $stdClass->class,
73
-                    'Value' => $value,
74
-                )));
75
-            } else {
76
-                $jobs->push(new ResqueJob(array(
77
-                    'Name' => $stdClass->class,
78
-                    'Value' => var_export($stdClass->args[0], true),
79
-                )));
80
-            }
81
-        }
57
+		$resqueJobs = Resque::redis()->lrange('queue:' . $this->Name, 0, -1);
58
+		if (!$resqueJobs) {
59
+			$jobs->push(new ResqueJob(array(
60
+				'Name' => 'null',
61
+				'Value' => 'null',
62
+			)));
63
+			return $jobs;
64
+		}
65
+		foreach ($resqueJobs as $idx => $job) {
66
+			$stdClass = json_decode($job);
67
+			if ($stdClass->class === 'CapistranoDeploy' || $stdClass->class === 'DeployJob') {
68
+				$value = $stdClass->args[0]->projectName
69
+					. ':' . $stdClass->args[0]->environment
70
+					. ' - ' . $stdClass->args[0]->sha;
71
+				$jobs->push(new ResqueJob(array(
72
+					'Name' => $stdClass->class,
73
+					'Value' => $value,
74
+				)));
75
+			} else {
76
+				$jobs->push(new ResqueJob(array(
77
+					'Name' => $stdClass->class,
78
+					'Value' => var_export($stdClass->args[0], true),
79
+				)));
80
+			}
81
+		}
82 82
 
83
-        return $jobs;
84
-    }
83
+		return $jobs;
84
+	}
85 85
 
86
-    /**
87
-     * @return boolean
88
-     */
89
-    public function canView()
90
-    {
91
-        return true;
92
-    }
86
+	/**
87
+	 * @return boolean
88
+	 */
89
+	public function canView()
90
+	{
91
+		return true;
92
+	}
93 93
 
94
-    /**
95
-     * @return bool
96
-     */
97
-    public function canEdit()
98
-    {
99
-        return true;
100
-    }
94
+	/**
95
+	 * @return bool
96
+	 */
97
+	public function canEdit()
98
+	{
99
+		return true;
100
+	}
101 101
 
102
-    /**
103
-     * @return bool
104
-     */
105
-    public function candelete()
106
-    {
107
-        return false;
108
-    }
102
+	/**
103
+	 * @return bool
104
+	 */
105
+	public function candelete()
106
+	{
107
+		return false;
108
+	}
109 109
 
110
-    /**
111
-     * @return bool
112
-     */
113
-    public function cancreate()
114
-    {
115
-        return false;
116
-    }
110
+	/**
111
+	 * @return bool
112
+	 */
113
+	public function cancreate()
114
+	{
115
+		return false;
116
+	}
117 117
 
118
-    /**
119
-     * @param string $property
120
-     * @return mixed
121
-     */
122
-    public function __get($property)
123
-    {
124
-        if (isset($this->record[$property])) {
125
-            return $this->record[$property];
126
-        }
127
-        return null;
128
-    }
118
+	/**
119
+	 * @param string $property
120
+	 * @return mixed
121
+	 */
122
+	public function __get($property)
123
+	{
124
+		if (isset($this->record[$property])) {
125
+			return $this->record[$property];
126
+		}
127
+		return null;
128
+	}
129 129
 }
Please login to merge, or discard this patch.