3 * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
5 * This file is a part of Fusionforge.
7 * Fusionforge 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 * Fusionforge 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 Fusionforge. If not, see <http://www.gnu.org/licenses/>.
21 require_once 'hudson.class.php';
22 require_once 'HudsonJobURLMalformedException.class.php';
23 require_once 'HudsonJobURLFileException.class.php';
24 require_once 'HudsonJobURLFileNotFoundException.class.php';
28 protected $hudson_job_url;
29 protected $hudson_dobuild_url;
30 protected $hudson_config_job_url;
32 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";
49 $controler = $this->getHudsonControler();
50 $this->icons_path = $controler->getIconsPath();
51 $this->_setStreamContext();
52 $this->buildJobObject();
55 function getHudsonControler() {
59 public function buildJobObject() {
60 $this->dom_job = $this->_getXMLObject($this->hudson_job_url);
63 public function configJobObject() {
64 if ($this->config_job) {
67 $this->config_job = $this->_getXMLObject($this->hudson_config_job_url);
70 protected function _getXMLObject($hudson_job_url) {
71 // If enabled, use APC cache (1sec) to reduce RSS fetching that may cause big delays.
72 if (function_exists('apc_fetch')) {
73 $xmlstr = apc_fetch($hudson_job_url);
74 if ($xmlstr === false) {
75 $xmlstr = @file_get_contents($hudson_job_url, false, $this->context);
76 apc_store($hudson_job_url, $xmlstr, 1);
79 $xmlstr = @file_get_contents($hudson_job_url, false, $this->context);
82 if ($xmlstr !== false) {
83 $xmlobj = simplexml_load_string($xmlstr);
84 if ($xmlobj !== false) {
87 throw new HudsonJobURLFileException(vsprintf(_("Unable to read file at URL: %s"), array($hudson_job_url)));
90 throw new HudsonJobURLFileNotFoundException(vsprintf(_("File not found at URL: %s"), array($hudson_job_url)));
94 private function _setStreamContext() {
95 if (array_key_exists('sys_proxy', $GLOBALS) && $GLOBALS['sys_proxy']) {
99 'proxy' => $GLOBALS['sys_proxy'],
100 'request_fulluri' => True,
104 $this->context = stream_context_create($context_opt);
106 $this->context = null;
110 function getProjectStyle() {
111 return $this->dom_job->getName();
115 return $this->dom_job->name;
119 return $this->dom_job->url;
122 function getColor() {
123 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"));
134 function getStatus() {
135 switch ($this->getColor()) {
137 // The last build was successful.
141 // The last build was successful. A new build is in progress.
142 return _("In progress");
145 // The last build was successful but unstable. This is primarily used to represent test failures.
146 return _("Unstable");
149 // The last build was successful but unstable. This is primarily used to represent test failures. A new build is in progress.
150 return _("In progress");
153 // The last build fatally failed.
157 // The last build fatally failed. A new build is in progress.
158 return _("In progress");
161 // The project has never been built before, or the project is disabled.
165 // The project has never been built before, or the project is disabled. The first build of this project is in progress.
166 return _("In progress");
169 // Can we have anime icons here?
170 return _("Unknown status");
175 function getIconsPath() {
176 return $this->icons_path;
179 function getStatusIcon() {
180 switch ($this->getColor()) {
182 // The last build was successful.
183 return $this->getIconsPath()."status_blue.png";
186 // The last build was successful. A new build is in progress.
187 return $this->getIconsPath()."status_blue.png";
190 // The last build was successful but unstable. This is primarily used to represent test failures.
191 return $this->getIconsPath()."status_yellow.png";
194 // The last build was successful but unstable. A new build is in progress.
195 return $this->getIconsPath()."status_yellow.png";
198 // The last build fatally failed.
199 return $this->getIconsPath()."status_red.png";
202 // The last build fatally failed. A new build is in progress.
203 return $this->getIconsPath()."status_red.png";
206 // The project has never been built before, or the project is disabled.
207 return $this->getIconsPath()."status_grey.png";
210 // The first build of the project is in progress.
211 return $this->getIconsPath()."status_grey.png";
214 // Can we have anime icons here?
215 return $this->getIconsPath()."status_unknown.png";
220 function isBuildable() {
221 return ($this->dom_job->buildable == "true");
224 function hasBuilds() {
225 return ((int)$this->getLastBuildNumber() !== 0);
228 function getLastBuildNumber() {
229 return $this->dom_job->lastBuild->number;
232 function getLastBuildUrl() {
233 return $this->dom_job->lastBuild->url;
236 function getLastSuccessfulBuildNumber() {
237 return $this->dom_job->lastSuccessfulBuild->number;
240 function getLastSuccessfulBuildUrl() {
241 return $this->dom_job->lastSuccessfulBuild->url;
244 function getLastFailedBuildNumber() {
245 return $this->dom_job->lastFailedBuild->number;
248 function getLastFailedBuildUrl() {
249 return $this->dom_job->lastFailedBuild->url;
252 function getNextBuildNumber() {
253 return $this->dom_job->nextBuildNumber;
256 function getHealthScores() {
258 foreach ($this->dom_job->healthReport as $health_report) {
259 $scores[] = $health_report->score;
264 function getHealthDescriptions() {
266 foreach ($this->dom_job->healthReport as $health_report) {
267 $scores[] = $health_report->description;
272 function getHealthAverageScore() {
273 $arr = $this->getHealthScores();
275 foreach ($arr as $score) {
280 return floor($sum/$num);
286 function getWeatherReportIcon() {
287 $score = $this->getHealthAverageScore();
289 return $this->getIconsPath()."health_80_plus.gif";
290 } elseif ($score >= 60) {
291 return $this->getIconsPath()."health_60_to_79.gif";
292 } elseif ($score >= 40) {
293 return $this->getIconsPath()."health_40_to_59.gif";
294 } elseif ($score >= 20) {
295 return $this->getIconsPath()."health_20_to_39.gif";
297 return $this->getIconsPath()."health_00_to_19.gif";
301 function getSvnLocation() {
302 $this->configJobObject();
303 return $this->config_job->scm->locations->{'hudson.scm.SubversionSCM_-ModuleLocation'}->remote;
307 * Launch a Build for this job on the Continuous Integration server.
309 * @exception if unable to open build URL or if response is an error
311 * @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.
312 * @return response of build call.
314 function launchBuild($token = null) {
315 $url = $this->hudson_dobuild_url;
316 if ($token != null) {
317 $url .= '?token='.$token;
319 $params = array('http' => array(
323 $ctx = stream_context_create($params);
324 $fp = fopen($url, 'rb', false, $ctx);
326 throw new Exception("Problem with $url");
328 $response = stream_get_contents($fp);
329 if ($response === false) {
330 throw new Exception("Problem reading data from $url");