diff --git a/PHPCI/Controller/BuildStatusController.php b/PHPCI/Controller/BuildStatusController.php
index 06f9400b..62442bf8 100644
--- a/PHPCI/Controller/BuildStatusController.php
+++ b/PHPCI/Controller/BuildStatusController.php
@@ -15,6 +15,7 @@ use b8\Store;
use PHPCI\BuildFactory;
use PHPCI\Model\Project;
use PHPCI\Model\Build;
+use PHPCI\Service\BuildStatusService;
/**
* Build Status Controller - Allows external access to build status information / images.
@@ -24,10 +25,9 @@ use PHPCI\Model\Build;
*/
class BuildStatusController extends \PHPCI\Controller
{
- /**
- * @var \PHPCI\Store\ProjectStore
- */
+ /* @var \PHPCI\Store\ProjectStore */
protected $projectStore;
+ /* @var \PHPCI\Store\BuildStore */
protected $buildStore;
/**
@@ -70,6 +70,62 @@ class BuildStatusController extends \PHPCI\Controller
return $status;
}
+ /**
+ * Displays projects information in ccmenu format
+ *
+ * @param $projectId
+ * @return bool
+ * @throws \Exception
+ * @throws b8\Exception\HttpException
+ */
+ public function ccxml($projectId)
+ {
+ /* @var Project $project */
+ $project = $this->projectStore->getById($projectId);
+ $xml = new \SimpleXMLElement('');
+
+ if (!$project instanceof Project || !$project->getAllowPublicStatus()) {
+ return $this->renderXml($xml);
+ }
+
+ try {
+ $branchList = $this->buildStore->getBuildBranches($projectId);
+
+ if (!$branchList) {
+ $branchList = array($project->getBranch());
+ }
+
+ foreach ($branchList as $branch) {
+ $buildStatusService = new BuildStatusService($branch, $project, $project->getLatestBuild($branch));
+ if ($attributes = $buildStatusService->toArray()) {
+ $projectXml = $xml->addChild('Project');
+ foreach ($attributes as $attributeKey => $attributeValue) {
+ $projectXml->addAttribute($attributeKey, $attributeValue);
+ }
+ }
+ }
+
+ } catch (\Exception $e) {
+ $xml = new \SimpleXMLElement('');
+ }
+
+ return $this->renderXml($xml);
+ }
+
+ /**
+ * @param \SimpleXMLElement $xml
+ * @return bool
+ */
+ protected function renderXml(\SimpleXMLElement $xml = null)
+ {
+ $this->response->setHeader('Content-Type', 'text/xml');
+ $this->response->setContent($xml->asXML());
+ $this->response->flush();
+ echo $xml->asXML();
+
+ return true;
+ }
+
/**
* Returns the appropriate build status image in SVG format for a given project.
*/
diff --git a/PHPCI/Service/BuildStatusService.php b/PHPCI/Service/BuildStatusService.php
new file mode 100644
index 00000000..b4f3c009
--- /dev/null
+++ b/PHPCI/Service/BuildStatusService.php
@@ -0,0 +1,222 @@
+project = $project;
+ $this->branch = $branch;
+ $this->build = $build;
+ if ($this->build) {
+ $this->loadParentBuild($isParent);
+ }
+ if (defined('PHPCI_URL')) {
+ $this->setUrl(PHPCI_URL);
+ }
+ }
+
+ /**
+ * @param $url
+ */
+ public function setUrl($url)
+ {
+ $this->url = $url;
+ }
+
+ /**
+ * @return Build
+ */
+ public function getBuild()
+ {
+ return $this->build;
+ }
+
+ /**
+ * @param bool $isParent
+ * @throws \Exception
+ */
+ protected function loadParentBuild($isParent = true)
+ {
+ if ($isParent === false && !$this->isFinished()) {
+ $lastFinishedBuild = $this->project->getLatestBuild($this->branch, $this->finishedStatusIds);
+
+ if ($lastFinishedBuild) {
+ $this->prevService = new BuildStatusService(
+ $this->branch,
+ $this->project,
+ $lastFinishedBuild,
+ true
+ );
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function getActivity()
+ {
+ if (in_array($this->build->getStatus(), $this->finishedStatusIds)) {
+ return 'Sleeping';
+ } elseif ($this->build->getStatus() == Build::STATUS_NEW) {
+ return 'Pending';
+ } elseif ($this->build->getStatus() == Build::STATUS_RUNNING) {
+ return 'Building';
+ }
+ return 'Unknown';
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->project->getTitle() . ' / ' . $this->branch;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isFinished()
+ {
+ if (in_array($this->build->getStatus(), $this->finishedStatusIds)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return null|Build
+ */
+ public function getFinishedBuildInfo()
+ {
+ if ($this->isFinished()) {
+ return $this->build;
+ } elseif ($this->prevService) {
+ return $this->prevService->getBuild();
+ }
+ return null;
+ }
+
+ /**
+ * @return int|string
+ */
+ public function getLastBuildLabel()
+ {
+ if ($buildInfo = $this->getFinishedBuildInfo()) {
+ return $buildInfo->getId();
+ }
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function getLastBuildTime()
+ {
+ $dateFormat = 'Y-m-d\\TH:i:sO';
+ if ($buildInfo = $this->getFinishedBuildInfo()) {
+ return ($buildInfo->getFinished()) ? $buildInfo->getFinished()->format($dateFormat) : '';
+ }
+ return '';
+ }
+
+ /**
+ * @param Build $build
+ * @return string
+ */
+ public function getBuildStatus(Build $build)
+ {
+ switch ($build->getStatus()) {
+ case Build::STATUS_SUCCESS:
+ return 'Success';
+ case Build::STATUS_FAILED:
+ return 'Failure';
+ }
+ return 'Unknown';
+ }
+
+ /**
+ * @return string
+ */
+ public function getLastBuildStatus()
+ {
+ if ($build = $this->getFinishedBuildInfo()) {
+ return $this->getBuildStatus($build);
+ }
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function getBuildUrl()
+ {
+ return $this->url . 'build/view/' . $this->build->getId();
+ }
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ if (!$this->build) {
+ return array();
+ }
+ return array(
+ 'name' => $this->getName(),
+ 'activity' => $this->getActivity(),
+ 'lastBuildLabel' => $this->getLastBuildLabel(),
+ 'lastBuildStatus' => $this->getLastBuildStatus(),
+ 'lastBuildTime' => $this->getLastBuildTime(),
+ 'webUrl' => $this->getBuildUrl(),
+ );
+ }
+}
diff --git a/PHPCI/Store/BuildStore.php b/PHPCI/Store/BuildStore.php
index 3a4c0ddc..7519a12f 100644
--- a/PHPCI/Store/BuildStore.php
+++ b/PHPCI/Store/BuildStore.php
@@ -107,6 +107,27 @@ class BuildStore extends BuildStoreBase
}
}
+ /**
+ * Returns all registered branches for project
+ *
+ * @param $projectId
+ * @return array
+ * @throws \Exception
+ */
+ public function getBuildBranches($projectId)
+ {
+ $query = 'SELECT DISTINCT `branch` FROM `build` WHERE `project_id` = :project_id';
+ $stmt = Database::getConnection('read')->prepare($query);
+ $stmt->bindValue(':project_id', $projectId);
+
+ if ($stmt->execute()) {
+ $res = $stmt->fetchAll(\PDO::FETCH_COLUMN);
+ return $res;
+ } else {
+ return array();
+ }
+ }
+
/**
* Return build metadata by key, project and optionally build id.
* @param $key
diff --git a/Tests/PHPCI/Service/BuiltStatusServiceTest.php b/Tests/PHPCI/Service/BuiltStatusServiceTest.php
new file mode 100644
index 00000000..91e115e4
--- /dev/null
+++ b/Tests/PHPCI/Service/BuiltStatusServiceTest.php
@@ -0,0 +1,212 @@
+
+ */
+class BuildStatusServiceTest extends \PHPUnit_Framework_TestCase
+{
+ const BRANCH = 'master';
+
+ /** @var Project */
+ protected $project;
+
+ protected $timezone;
+
+ public function setUp()
+ {
+ $project = new Project();
+ $project->setId(3);
+ $project->setBranch(self::BRANCH);
+ $project->setTitle('Test');
+
+ $this->project = $project;
+ $this->timezone = date_default_timezone_get();
+
+ date_default_timezone_set('UTC');
+ }
+
+ public function tearDown()
+ {
+ date_default_timezone_set($this->timezone);
+ }
+
+ /**
+ * @param $configId
+ * @param bool $setProject
+ * @return Build
+ */
+ protected function getBuild($configId, $setProject = true)
+ {
+ $config = array(
+ '1' => array(
+ 'status' => Build::STATUS_RUNNING,
+ 'id' => 77,
+ 'finishDateTime' => null,
+ 'startedDate' => '2014-10-25 21:20:02',
+ 'previousBuild' => null,
+ ),
+ '2' => array(
+ 'status' => Build::STATUS_RUNNING,
+ 'id' => 78,
+ 'finishDateTime' => null,
+ 'startedDate' => '2014-10-25 21:20:02',
+ 'previousBuild' => 4,
+ ),
+ '3' => array(
+ 'status' => Build::STATUS_SUCCESS,
+ 'id' => 7,
+ 'finishDateTime' => '2014-10-25 21:50:02',
+ 'startedDate' => '2014-10-25 21:20:02',
+ 'previousBuild' => null,
+ ),
+ '4' => array(
+ 'status' => Build::STATUS_FAILED,
+ 'id' => 13,
+ 'finishDateTime' => '2014-10-13 13:13:13',
+ 'previousBuild' => null,
+ ),
+ '5' => array(
+ 'status' => Build::STATUS_NEW,
+ 'id' => 1000,
+ 'finishDateTime' => '2014-12-25 21:12:21',
+ 'previousBuild' => 3,
+ )
+ );
+
+ $build = new Build();
+ $build->setId($config[$configId]['id']);
+ $build->setBranch(self::BRANCH);
+ $build->setStatus($config[$configId]['status']);
+ if ($config[$configId]['finishDateTime']) {
+ $build->setFinished(new \DateTime($config[$configId]['finishDateTime']));
+ }
+ if (!empty($config[$configId]['startedDate'])) {
+ $build->setStarted(new \DateTime('2014-10-25 21:20:02'));
+ }
+
+ $project = $this->getProjectMock($config[$configId]['previousBuild'], $setProject);
+
+ $build->setProjectObject($project);
+
+ return $build;
+ }
+
+ /**
+ * @param null|int $prevBuildId
+ * @param bool $setProject
+ * @return Project
+ */
+ protected function getProjectMock($prevBuildId = null, $setProject = true) {
+
+ $project = $this->getMock('PHPCI\Model\Project', array('getLatestBuild'));
+
+ $prevBuild = ($prevBuildId) ? $this->getBuild($prevBuildId, false) : null;
+
+ $project->expects($this->any())
+ ->method('getLatestBuild')
+ ->will($this->returnValue($prevBuild));
+
+ /* @var $project Project */
+
+ $project->setId(3);
+ $project->setBranch(self::BRANCH);
+ $project->setTitle('Test');
+
+ if ($setProject) {
+ $this->project = $project;
+ }
+
+ return $project;
+
+ }
+
+ /**
+ * @dataProvider finishedProvider
+ *
+ * @param int $buildConfigId
+ * @param array $expectedResult
+ */
+ public function testFinished($buildConfigId, array $expectedResult)
+ {
+ $build = $this->getBuild($buildConfigId);
+ $service = new BuildStatusService(self::BRANCH, $this->project, $build);
+ $service->setUrl('http://phpci.dev/');
+ $this->assertEquals($expectedResult, $service->toArray());
+ }
+
+ public function finishedProvider()
+ {
+ return array(
+ 'buildingStatus' => array(
+ 1,
+ array(
+ 'name' => 'Test / master',
+ 'activity' => 'Building',
+ 'lastBuildLabel' => '',
+ 'lastBuildStatus' => '',
+ 'lastBuildTime' => '',
+ 'webUrl' => 'http://phpci.dev/build/view/77',
+ )
+ ),
+ 'buildingStatusWithPrev' => array(
+ 2,
+ array(
+ 'name' => 'Test / master',
+ 'activity' => 'Building',
+ 'lastBuildLabel' => 13,
+ 'lastBuildStatus' => 'Failure',
+ 'lastBuildTime' => '2014-10-13T13:13:13+0000',
+ 'webUrl' => 'http://phpci.dev/build/view/78',
+ )
+ ),
+ 'successStatus' => array(
+ 3,
+ array(
+ 'name' => 'Test / master',
+ 'activity' => 'Sleeping',
+ 'lastBuildLabel' => 7,
+ 'lastBuildStatus' => 'Success',
+ 'lastBuildTime' => '2014-10-25T21:50:02+0000',
+ 'webUrl' => 'http://phpci.dev/build/view/7',
+ )
+ ),
+ 'failureStatus' => array(
+ 4,
+ array(
+ 'name' => 'Test / master',
+ 'activity' => 'Sleeping',
+ 'lastBuildLabel' => 13,
+ 'lastBuildStatus' => 'Failure',
+ 'lastBuildTime' => '2014-10-13T13:13:13+0000',
+ 'webUrl' => 'http://phpci.dev/build/view/13',
+ )
+ ),
+ 'pending' => array(
+ 5,
+ array(
+ 'name' => 'Test / master',
+ 'activity' => 'Pending',
+ 'lastBuildLabel' => 7,
+ 'lastBuildStatus' => 'Success',
+ 'lastBuildTime' => '2014-10-25T21:50:02+0000',
+ 'webUrl' => 'http://phpci.dev/build/view/1000',
+ )
+ ),
+ );
+ }
+}
\ No newline at end of file