Allow see project build status in cctray xml format
Refactoring is done for BuildStatus information. - Fixed all phpcs, phpmd errors - Added test for my code (hurray 100 tests already :D) Closed #705
This commit is contained in:
parent
a22390c83d
commit
8fc4c51d54
|
@ -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('<Projects/>');
|
||||
|
||||
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('<projects/>');
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
|
222
PHPCI/Service/BuildStatusService.php
Normal file
222
PHPCI/Service/BuildStatusService.php
Normal file
|
@ -0,0 +1,222 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPCI - Continuous Integration for PHP
|
||||
*
|
||||
* @copyright Copyright 2014, Block 8 Limited.
|
||||
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||
* @link https://www.phptesting.org/
|
||||
*/
|
||||
|
||||
namespace PHPCI\Service;
|
||||
|
||||
use PHPCI\Model\Project;
|
||||
use PHPCI\Model\Build;
|
||||
|
||||
/**
|
||||
* Class BuildStatusService
|
||||
* @package PHPCI\Service
|
||||
*/
|
||||
class BuildStatusService
|
||||
{
|
||||
/* @var BuildStatusService */
|
||||
protected $prevService = null;
|
||||
|
||||
/* @var Project */
|
||||
protected $project;
|
||||
|
||||
/** @var string */
|
||||
protected $branch;
|
||||
|
||||
/* @var Build */
|
||||
protected $build;
|
||||
|
||||
/** @var string */
|
||||
protected $url;
|
||||
|
||||
/** @var array */
|
||||
protected $finishedStatusIds = array(
|
||||
Build::STATUS_SUCCESS,
|
||||
Build::STATUS_FAILED,
|
||||
);
|
||||
|
||||
/**
|
||||
* @param $branch
|
||||
* @param Project $project
|
||||
* @param Build $build
|
||||
* @param bool $isParent
|
||||
*/
|
||||
public function __construct(
|
||||
$branch,
|
||||
Project $project,
|
||||
Build $build = null,
|
||||
$isParent = false
|
||||
) {
|
||||
$this->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(),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
212
Tests/PHPCI/Service/BuiltStatusServiceTest.php
Normal file
212
Tests/PHPCI/Service/BuiltStatusServiceTest.php
Normal file
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPCI - Continuous Integration for PHP
|
||||
*
|
||||
* @copyright Copyright 2014, Block 8 Limited.
|
||||
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||
* @link http://www.phptesting.org/
|
||||
*/
|
||||
|
||||
namespace PHPCI\Service\Tests;
|
||||
|
||||
use PHPCI\Model\Build;
|
||||
use PHPCI\Model\Project;
|
||||
use PHPCI\Service\BuildService;
|
||||
use PHPCI\Service\BuildStatusService;
|
||||
|
||||
/**
|
||||
* Unit tests for the ProjectService class.
|
||||
* @author Dan Cryer <dan@block8.co.uk>
|
||||
*/
|
||||
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',
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue