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.
140 // The last build was successful. A new build is in progress.
141 return _("In progress");
143 // The last build was successful but unstable. This is primarily used to represent test failures.
144 return _("Unstable");
146 // The last build was successful but unstable. This is primarily used to represent test failures. A new build is in progress.
147 return _("In progress");
149 // The last build fatally failed.
152 // The last build fatally failed. A new build is in progress.
153 return _("In progress");
155 // The project has never been built before, or the project is disabled.
158 // The project has never been built before, or the project is disabled. The first build of this project is in progress.
159 return _("In progress");
161 // Can we have anime icons here?
162 return _("Unknown status");
166 function getIconsPath() {
167 return $this->icons_path;
170 function getStatusIcon() {
171 switch ($this->getColor()) {
173 // The last build was successful.
174 return $this->getIconsPath()."status_blue.png";
176 // The last build was successful. A new build is in progress.
177 return $this->getIconsPath()."status_blue.png";
179 // The last build was successful but unstable. This is primarily used to represent test failures.
180 return $this->getIconsPath()."status_yellow.png";
182 // The last build was successful but unstable. A new build is in progress.
183 return $this->getIconsPath()."status_yellow.png";
185 // The last build fatally failed.
186 return $this->getIconsPath()."status_red.png";
188 // The last build fatally failed. A new build is in progress.
189 return $this->getIconsPath()."status_red.png";
191 // The project has never been built before, or the project is disabled.
192 return $this->getIconsPath()."status_grey.png";
194 // The first build of the project is in progress.
195 return $this->getIconsPath()."status_grey.png";
197 // Can we have anime icons here?
198 return $this->getIconsPath()."status_unknown.png";
202 function isBuildable() {
203 return ($this->dom_job->buildable == "true");
206 function hasBuilds() {
207 return ((int)$this->getLastBuildNumber() !== 0);
210 function getLastBuildNumber() {
211 return $this->dom_job->lastBuild->number;
214 function getLastBuildUrl() {
215 return $this->dom_job->lastBuild->url;
218 function getLastSuccessfulBuildNumber() {
219 return $this->dom_job->lastSuccessfulBuild->number;
222 function getLastSuccessfulBuildUrl() {
223 return $this->dom_job->lastSuccessfulBuild->url;
226 function getLastFailedBuildNumber() {
227 return $this->dom_job->lastFailedBuild->number;
230 function getLastFailedBuildUrl() {
231 return $this->dom_job->lastFailedBuild->url;
234 function getNextBuildNumber() {
235 return $this->dom_job->nextBuildNumber;
238 function getHealthScores() {
240 foreach ($this->dom_job->healthReport as $health_report) {
241 $scores[] = $health_report->score;
246 function getHealthDescriptions() {
248 foreach ($this->dom_job->healthReport as $health_report) {
249 $descs[] = $health_report->description;
254 function getHealthAverageScore() {
255 $arr = $this->getHealthScores();
257 foreach ($arr as $score) {
262 return floor($sum/$num);
268 function getWeatherReportIcon() {
269 $score = $this->getHealthAverageScore();
271 return $this->getIconsPath()."health_80_plus.gif";
272 } elseif ($score >= 60) {
273 return $this->getIconsPath()."health_60_to_79.gif";
274 } elseif ($score >= 40) {
275 return $this->getIconsPath()."health_40_to_59.gif";
276 } elseif ($score >= 20) {
277 return $this->getIconsPath()."health_20_to_39.gif";
279 return $this->getIconsPath()."health_00_to_19.gif";
283 function getSvnLocation() {
284 $this->configJobObject();
285 return $this->config_job->scm->locations->{'hudson.scm.SubversionSCM_-ModuleLocation'}->remote;
289 * Launch a Build for this job on the Continuous Integration server.
291 * @exception if unable to open build URL or if response is an error
293 * @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.
294 * @return response of build call.
296 function launchBuild($token = null) {
297 $url = $this->hudson_dobuild_url;
298 if ($token != null) {
299 $url .= '?token='.$token;
301 $params = array('http' => array(
305 $ctx = stream_context_create($params);
306 $fp = fopen($url, 'rb', false, $ctx);
308 throw new Exception("Problem with $url");
310 $response = stream_get_contents($fp);
311 if ($response === false) {
312 throw new Exception("Problem reading data from $url");