3 * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
5 * This file is a part of Codendi.
7 * Codendi is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Codendi is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Codendi. If not, see <http://www.gnu.org/licenses/>.
20 require_once('hudson.class.php');
21 require_once('HudsonJobURLMalformedException.class.php');
22 require_once('HudsonJobURLFileException.class.php');
23 require_once('HudsonJobURLFileNotFoundException.class.php');
27 protected $hudson_job_url;
28 protected $hudson_dobuild_url;
29 protected $hudson_config_job_url;
31 protected $config_job;
37 * Construct an Hudson job from a job URL
39 function HudsonJob($hudson_job_url) {
40 $parsed_url = parse_url($hudson_job_url);
42 if ( ! $parsed_url || ! array_key_exists('scheme', $parsed_url) ) {
43 throw new HudsonJobURLMalformedException(vsprintf(_("Wrong Job URL: %s"), array($hudson_job_url)));
46 $this->hudson_job_url = $hudson_job_url . "/api/xml";
47 $this->hudson_dobuild_url = $hudson_job_url . "/build";
48 $this->hudson_config_job_url = $hudson_job_url . "/config.xml";
50 $controler = $this->getHudsonControler();
51 $this->icons_path = $controler->getIconsPath();
53 $this->_setStreamContext();
55 $this->buildJobObject();
58 function getHudsonControler() {
62 public function buildJobObject() {
63 $this->dom_job = $this->_getXMLObject($this->hudson_job_url);
66 public function configJobObject() {
67 if ($this->config_job) {
70 $this->config_job = $this->_getXMLObject($this->hudson_config_job_url);
73 protected function _getXMLObject($hudson_job_url) {
75 // If enabled, use APC cache (1sec) to reduce RSS fetching that may cause big delays.
76 if (function_exists('apc_fetch')) {
77 $xmlstr = apc_fetch($hudson_job_url);
78 if ($xmlstr === false) {
79 $xmlstr = @file_get_contents($hudson_job_url, false, $this->context);
80 apc_store($hudson_job_url, $xmlstr, 1);
83 $xmlstr = @file_get_contents($hudson_job_url, false, $this->context);
86 if ($xmlstr !== false) {
87 $xmlobj = simplexml_load_string($xmlstr);
88 if ($xmlobj !== false) {
91 throw new HudsonJobURLFileException(vsprintf(_("Unable to read file at URL: %s"), array($hudson_job_url)));
94 throw new HudsonJobURLFileNotFoundException(vsprintf(_("File not found at URL: %s"), array($hudson_job_url)));
98 private function _setStreamContext() {
99 if (array_key_exists('sys_proxy', $GLOBALS) && $GLOBALS['sys_proxy']) {
100 $context_opt = array(
103 'proxy' => $GLOBALS['sys_proxy'],
104 'request_fulluri' => True,
108 $this->context = stream_context_create($context_opt);
110 $this->context = null;
114 function getProjectStyle() {
115 return $this->dom_job->getName();
118 return $this->dom_job->name;
121 return $this->dom_job->url;
123 function getColor() {
124 return $this->dom_job->color;
126 function getColorNoAnime() {
127 $color = $this->getColor();
128 if (strpos($color, "_anime")) {
129 $color = substr($color, 0, strpos($color, "_anime"));
133 function getStatus() {
134 switch ($this->getColor()) {
136 // The last build was successful.
140 // The last build was successful. A new build is in progress.
141 return _("In progress");
144 // The last build was successful but unstable. This is primarily used to represent test failures.
145 return _("Unstable");
148 // The last build was successful but unstable. This is primarily used to represent test failures. A new build is in progress.
149 return _("In progress");
152 // The last build fatally failed.
156 // The last build fatally failed. A new build is in progress.
157 return _("In progress");
160 // The project has never been built before, or the project is disabled.
164 // The project has never been built before, or the project is disabled. The first build of this project is in progress.
165 return _("In progress");
168 // Can we have anime icons here?
169 return _("Unknown status");
174 function getIconsPath() {
175 return $this->icons_path;
177 function getStatusIcon() {
178 switch ($this->getColor()) {
180 // The last build was successful.
181 return $this->getIconsPath()."status_blue.png";
184 // The last build was successful. A new build is in progress.
185 return $this->getIconsPath()."status_blue.png";
188 // The last build was successful but unstable. This is primarily used to represent test failures.
189 return $this->getIconsPath()."status_yellow.png";
192 // The last build was successful but unstable. A new build is in progress.
193 return $this->getIconsPath()."status_yellow.png";
196 // The last build fatally failed.
197 return $this->getIconsPath()."status_red.png";
200 // The last build fatally failed. A new build is in progress.
201 return $this->getIconsPath()."status_red.png";
204 // The project has never been built before, or the project is disabled.
205 return $this->getIconsPath()."status_grey.png";
208 // The first build of the project is in progress.
209 return $this->getIconsPath()."status_grey.png";
212 // Can we have anime icons here?
213 return $this->getIconsPath()."status_unknown.png";
218 function isBuildable() {
219 return ($this->dom_job->buildable == "true");
222 function hasBuilds() {
223 return ((int)$this->getLastBuildNumber() !== 0);
226 function getLastBuildNumber() {
227 return $this->dom_job->lastBuild->number;
229 function getLastBuildUrl() {
230 return $this->dom_job->lastBuild->url;
233 function getLastSuccessfulBuildNumber() {
234 return $this->dom_job->lastSuccessfulBuild->number;
236 function getLastSuccessfulBuildUrl() {
237 return $this->dom_job->lastSuccessfulBuild->url;
240 function getLastFailedBuildNumber() {
241 return $this->dom_job->lastFailedBuild->number;
243 function getLastFailedBuildUrl() {
244 return $this->dom_job->lastFailedBuild->url;
247 function getNextBuildNumber() {
248 return $this->dom_job->nextBuildNumber;
251 function getHealthScores() {
253 foreach ($this->dom_job->healthReport as $health_report) {
254 $scores[] = $health_report->score;
258 function getHealthDescriptions() {
260 foreach ($this->dom_job->healthReport as $health_report) {
261 $scores[] = $health_report->description;
265 function getHealthAverageScore() {
266 $arr = $this->getHealthScores();
268 foreach ($arr as $score) {
273 return floor($sum/$num);
279 function getWeatherReportIcon() {
280 $score = $this->getHealthAverageScore();
282 return $this->getIconsPath()."health_80_plus.gif";
283 } elseif ($score >= 60) {
284 return $this->getIconsPath()."health_60_to_79.gif";
285 } elseif ($score >= 40) {
286 return $this->getIconsPath()."health_40_to_59.gif";
287 } elseif ($score >= 20) {
288 return $this->getIconsPath()."health_20_to_39.gif";
290 return $this->getIconsPath()."health_00_to_19.gif";
294 function getSvnLocation() {
295 $this->configJobObject();
296 return $this->config_job->scm->locations->{'hudson.scm.SubversionSCM_-ModuleLocation'}->remote;
300 * Launch a Build for this job on the Continuous Integration server.
302 * @exception if unable to open build URL or if response is an error
304 * @param string $token if CI server has activated security (login/password), then a token is mandatory to build jobs. This token is defined in the job configuration.
305 * @return response of build call.
307 function launchBuild($token = null) {
308 $url = $this->hudson_dobuild_url;
309 if ($token != null) {
310 $url .= '?token='.$token;
312 $params = array('http' => array(
316 $ctx = stream_context_create($params);
317 $fp = fopen($url, 'rb', false, $ctx);
319 throw new Exception("Problem with $url");
321 $response = stream_get_contents($fp);
322 if ($response === false) {
323 throw new Exception("Problem reading data from $url");