Completed
Pull Request — master (#603)
by Stig
03:57
created

DeployPlanDispatcher::getAPIResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 12
rs 9.4285
c 1
b 0
f 0
cc 1
eloc 10
nc 1
nop 2
1
<?php
2
3
4
class DeployPlanDispatcher extends Dispatcher {
5
6
	const ACTION_PLAN = 'plan';
7
8
	/**
9
	 * @var array
10
	 */
11
	private static $action_types = [
12
		self::ACTION_PLAN
13
	];
14
15
	/**
16
	 * @var array
17
	 */
18
	public static $allowed_actions = [
19
		'gitupdate',
20
		'gitrefs',
21
	];
22
23
	/**
24
	 * @var \DNProject
25
	 */
26
	protected $project = null;
27
28
	/**
29
	 * @var \DNEnvironment
30
	 */
31
	protected $environment = null;
32
33
	public function init() {
34
		parent::init();
35
36
		$this->project = $this->getCurrentProject();
37
38
		if(!$this->project) {
39
			return $this->project404Response();
40
		}
41
42
		// Performs canView permission check by limiting visible projects
43
		$this->environment = $this->getCurrentEnvironment($this->project);
44
		if(!$this->environment) {
45
			return $this->environment404Response();
46
		}
47
	}
48
49
	/**
50
	 * @return string
51
	 */
52
	public function Link() {
53
		return \Controller::join_links($this->environment->Link(), self::ACTION_PLAN);
54
	}
55
56
	/**
57
	 *
58
	 * @param \SS_HTTPRequest $request
59
	 *
60
	 * @return \HTMLText|\SS_HTTPResponse
61
	 */
62
	public function index(\SS_HTTPRequest $request) {
63
		$this->setCurrentActionType(self::ACTION_PLAN);
64
		return $this->customise([
65
			'Environment' => $this->environment
66
		])->renderWith(['Plan', 'DNRoot']);
67
	}
68
69
	/**
70
	 * @param SS_HTTPRequest $request
71
	 * @return SS_HTTPResponse
72
	 */
73
	public function gitupdate(SS_HTTPRequest $request) {
74
		// @todo permissions
75
76
		switch($request->httpMethod()) {
77
			case 'POST':
78
				return $this->createFetch();
79
			case 'GET':
80
				return $this->getFetch($this->getRequest()->param('ID'));
81
			default:
82
				return $this->getAPIResponse('Method not allowed, requires POST or GET/{id}', 405);
83
		}
84
	}
85
86
	/**
87
	 * @param SS_HTTPRequest $request
88
	 *
89
	 * @return string
90
	 */
91
	public function gitrefs(\SS_HTTPRequest $request) {
92
93
		$refs = [];
94
		$order = 0;
95
		$refs[] = [
96
			'id' => ++$order,
97
			'label' => "Branch version",
98
			"description" => "Deploy the latest version of a branch",
99
			"list" => $this->getGitBranches($this->project)
100
		];
101
102
		$refs[] = [
103
			'id' => ++$order,
104
			'label' => "Tag version",
105
			"description" => "Deploy a tagged release",
106
			"list" => $this->getGitTags($this->project)
107
		];
108
109
		// @todo: the original was a tree that was keyed by environment, the
110
		// front-end dropdown needs to be changed to support that. brrrr.
111
		$prevDeploys = [];
112
		foreach($this->getGitPrevDeploys($this->project) as $env) {
113
			foreach($env as $deploy) {
114
				$prevDeploys[] = $deploy;
115
			}
116
		}
117
		$refs[] = [
118
			'id' => ++$order,
119
			'label' => "Redeploy a release that was previously deployed (to any environment",
120
			"description" => "Deploy a previous release",
121
			"list" => $prevDeploys
122
		];
123
124
		$body = json_encode($refs, JSON_PRETTY_PRINT);
125
		$this->getResponse()->addHeader('Content-Type', 'application/json');
126
		$this->getResponse()->setBody($body);
127
		return $body;
128
	}
129
130
	/**
131
	 * Generate the data structure used by the frontend component.
132
	 *
133
	 * @param string $name of the component
134
	 *
135
	 * @return array
136
	 */
137
	public function getModel($name) {
138
		return [
139
			'APIEndpoint' => Director::absoluteBaseURL().$this->Link()
140
		];
141
	}
142
143
	/**
144
	 * @param int $ID
145
	 * @return SS_HTTPResponse
146
	 */
147
	protected function getFetch($ID) {
148
		$ping = DNGitFetch::get()->byID($ID);
149
		if(!$ping) {
150
			return $this->getAPIResponse('Fetch not found', 404);
151
		}
152
		$output = [
153
			'id' => $ID,
154
			'status' => $ping->ResqueStatus(),
155
			'message' => array_filter(explode(PHP_EOL, $ping->LogContent()))
156
		];
157
158
		return $this->getAPIResponse($output, 200);
0 ignored issues
show
Documentation introduced by
$output is of type array<string,?,{"id":"in..."?","message":"array"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
159
	}
160
161
	/**
162
	 * @return SS_HTTPResponse
163
	 */
164 View Code Duplication
	protected function createFetch() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165
		/** @var DNGitFetch $fetch */
166
		$fetch = DNGitFetch::create();
167
		$fetch->ProjectID = $this->project->ID;
168
		$fetch->write();
169
		$fetch->start();
170
171
		$location = Director::absoluteBaseURL() . $this->Link() . '/gitupdate/' . $fetch->ID;
172
		$output = array(
173
			'message' => 'Fetch queued as job ' . $fetch->ResqueToken,
174
			'href' => $location,
175
		);
176
177
		$response = $this->getAPIResponse($output, 201);
0 ignored issues
show
Documentation introduced by
$output is of type array<string,string,{"me...ring","href":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
178
		$response->addHeader('Location', $location);
179
		return $response;
180
	}
181
182
	/**
183
	 * @param $project
184
	 *
185
	 * @return array
186
	 */
187
	protected function getGitBranches($project) {
188
		$branches = [];
189
		foreach($project->DNBranchList() as $branch) {
190
			$branches[] = [
191
				'key' => $branch->SHA(),
192
				'value' => $branch->Name(),
193
			];
194
		}
195
		return $branches;
196
	}
197
198
	/**
199
	 * @param $project
200
	 *
201
	 * @return array
202
	 */
203
	protected function getGitTags($project) {
204
		$tags = [];
205
		foreach($project->DNTagList()->setLimit(null) as $tag) {
206
			$tags[] = [
207
				'key' => $tag->SHA(),
208
				'value' => $tag->Name(),
209
			];
210
		}
211
		return $tags;
212
	}
213
214
	/**
215
	 * @param $project
216
	 *
217
	 * @return array
218
	 */
219
	protected function getGitPrevDeploys($project) {
220
		$redeploy = [];
221 View Code Duplication
		foreach($project->DNEnvironmentList() as $dnEnvironment) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
222
			$envName = $dnEnvironment->Name;
223
			$perEnvDeploys = [];
224
			foreach($dnEnvironment->DeployHistory() as $deploy) {
225
				$sha = $deploy->SHA;
226
227
				// Check if exists to make sure the newest deployment date is used.
228
				if(!isset($perEnvDeploys[$sha])) {
229
					$pastValue = sprintf(
230
						"%s (deployed %s)",
231
						substr($sha, 0, 8),
232
						$deploy->obj('LastEdited')->Ago()
233
					);
234
					$perEnvDeploys[$sha] = [
235
						'key' => $sha,
236
						'value' => $pastValue
237
					];
238
				}
239
			}
240
			if(!empty($perEnvDeploys)) {
241
				$redeploy[$envName] = array_values($perEnvDeploys);
242
			}
243
		}
244
		return $redeploy;
245
	}
246
247
	/**
248
	 * Return a simple response with a message
249
	 *
250
	 * @param string $message
251
	 * @param int $statusCode
252
	 * @return SS_HTTPResponse
253
	 */
254
	protected function getAPIResponse($message, $statusCode) {
255
		$output = [
256
			'message' => $message,
257
			'status_code' => $statusCode
258
		];
259
		$body = json_encode($output, JSON_PRETTY_PRINT);
260
		$response = $this->getResponse();
261
		$response->addHeader('Content-Type', 'application/json');
262
		$response->setBody($body);
263
		$response->setStatusCode($statusCode);
264
		return $response;
265
	}
266
}
267