From 653f4cb620dbe653ad67b5d8dc0ffed428cc6191 Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Fri, 17 May 2013 16:10:54 +0100 Subject: [PATCH] Adding build status images, both to the dashboard and as an external facing feature. Closes #43 --- PHPCI/Application.php | 4 +- PHPCI/Controller/BuildStatusController.php | 50 +++++++++++++++++++++ PHPCI/Model/Project.php | 23 ++++++++++ PHPCI/View/Index.phtml | 27 ++++++++++- assets/css/phpci.css | 22 ++++++++- assets/img/build-failed.png | Bin 0 -> 2059 bytes assets/img/build-ok.png | Bin 0 -> 1839 bytes assets/img/icon-build-failed.png | Bin 0 -> 282 bytes assets/img/icon-build-ok.png | Bin 0 -> 290 bytes assets/img/icon-build-pending.png | Bin 0 -> 292 bytes assets/img/icon-build-running.png | Bin 0 -> 284 bytes 11 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 PHPCI/Controller/BuildStatusController.php create mode 100644 assets/img/build-failed.png create mode 100644 assets/img/build-ok.png create mode 100644 assets/img/icon-build-failed.png create mode 100644 assets/img/icon-build-ok.png create mode 100644 assets/img/icon-build-pending.png create mode 100644 assets/img/icon-build-running.png diff --git a/PHPCI/Application.php b/PHPCI/Application.php index a284c7c5..fe3bcca4 100644 --- a/PHPCI/Application.php +++ b/PHPCI/Application.php @@ -27,9 +27,9 @@ class Application extends b8\Application // Validate the user's session unless it is a login/logout action or a web hook: $sessionAction = ($controllerName == 'Session' && in_array($this->action, array('login', 'logout'))); - $webhookAction = in_array($controllerName, array('Bitbucket', 'Github')); + $externalAction = in_array($controllerName, array('Bitbucket', 'Github', 'BuildStatus')); - if (!$webhookAction && !$sessionAction) { + if (!$externalAction && !$sessionAction) { $this->validateSession(); } diff --git a/PHPCI/Controller/BuildStatusController.php b/PHPCI/Controller/BuildStatusController.php new file mode 100644 index 00000000..e898405a --- /dev/null +++ b/PHPCI/Controller/BuildStatusController.php @@ -0,0 +1,50 @@ + +* @package PHPCI +* @subpackage Web +*/ +class BuildStatusController extends b8\Controller +{ + public function init() + { + $this->_projectStore = Store\Factory::getStore('Project'); + } + + /** + * Returns the appropriate build status image for a given project. + */ + public function image($projectId) + { + $branch = $this->getParam('branch', 'master'); + $project = $this->_projectStore->getById($projectId); + $status = 'ok'; + + if (isset($project) && $project instanceof Project) { + $build = $project->getLatestBuild($branch, array(2,3)); + + if (isset($build) && $build instanceof Build && $build->getStatus() != 2) { + $status = 'failed'; + } + } + + header('Content-Type: image/png'); + die(file_get_contents(APPLICATION_PATH . 'assets/img/build-' . $status . '.png')); + } +} diff --git a/PHPCI/Model/Project.php b/PHPCI/Model/Project.php index be1c808b..f2a435fd 100644 --- a/PHPCI/Model/Project.php +++ b/PHPCI/Model/Project.php @@ -10,6 +10,8 @@ namespace PHPCI\Model; use PHPCI\Model\Base\ProjectBase; +use PHPCI\Model\Build; +use b8\Store; /** * Project Model @@ -20,4 +22,25 @@ use PHPCI\Model\Base\ProjectBase; */ class Project extends ProjectBase { + public function getLatestBuild($branch = 'master', $status = null) + { + $criteria = array('branch' => $branch, 'project_id' => $this->getId()); + + if (isset($status)) { + $criteria['status'] = $status; + } + + $order = array('id' => 'DESC'); + $builds = Store\Factory::getStore('Build')->getWhere($criteria, 1, $start, array(), $order); + + if (is_array($builds['items']) && count($builds['items'])) { + $latest = array_shift($builds['items']); + + if (isset($latest) && $latest instanceof Build) { + return $latest; + } + } + + return null; + } } diff --git a/PHPCI/View/Index.phtml b/PHPCI/View/Index.phtml index 196164c4..2dcea736 100644 --- a/PHPCI/View/Index.phtml +++ b/PHPCI/View/Index.phtml @@ -10,8 +10,31 @@
  • - -
  • getTitle(); ?>
  • + getLatestBuild('master'); + + if (isset($build)) { + switch($build->getStatus()) + { + case 0: + $status = 'icon-build-pending'; + break; + case 1: + $status = 'icon-build-running'; + break; + case 3: + $status = 'icon-build-failed'; + break; + case 2: + default: + $status = 'icon-build-ok'; + break; + } + } + ?> +
  • getTitle(); ?>
  • diff --git a/assets/css/phpci.css b/assets/css/phpci.css index 076a5d59..bb0340c3 100644 --- a/assets/css/phpci.css +++ b/assets/css/phpci.css @@ -39,4 +39,24 @@ body font-size: 2em; margin: 0; padding: 0; - } \ No newline at end of file + } + +.icon-build-ok +{ + background: url('/assets/img/icon-build-ok.png') no-repeat top left; +} + +.icon-build-failed +{ + background: url('/assets/img/icon-build-failed.png') no-repeat top left; +} + +.icon-build-pending +{ + background: url('/assets/img/icon-build-pending.png') no-repeat top left; +} + +.icon-build-running +{ + background: url('/assets/img/icon-build-running.png') no-repeat top left; +} \ No newline at end of file diff --git a/assets/img/build-failed.png b/assets/img/build-failed.png new file mode 100644 index 0000000000000000000000000000000000000000..75b0893665fefa1b8198821d1f84660c3b037286 GIT binary patch literal 2059 zcmV+m2=w=fP)dbVG7wVRUJ4ZXi@?ZDjy4H!n3W zF*60>Ig$VX0338hSaefwW^{L9a%BKPWN%_+AVz6&Wp{6KYjYq&Q#En5<2C>Q2V_Y^ zK~!jg)tOIh6xSWcKQlZ211$AyQ!n18fhlPfsHw1}26HI(*bE2s&G-A>`@J`#5W?xxr}ac4ajLeqHlrwt!6w3=KKyW_LwGI- zm|lYZ?_sC~7K9K0Xwsm!xA)CrvG`G;P-xq*C|?4T8y&#&!vOk$_wK;^z#Z@f>FMb? zt13LivgQj5b(Ia^qHb`XpZB2 z0PKmfmg}1kBB%o>ic+>->H09j_F?~}HqtK2KWutIP&^Gj&>Y7}mm^FvEnm-?5!OG_nec0qikHOFz9qAXn3MF>GhM+c3KjR9#lZrq?yD4?n;U0q!i z3I!%7Cj-)sA3q-0bar+!H#f)Rp*E?G<4~;>i$zS+WbfX+*tU&f7@R+U9!=9&US1CR zip643jvYHjB9UNaWhLmZWV>h29y&WagZmvldX$S7FVf!LzQ)eBZEV{v8>8!sQm*W< zEVh{@kATO1nFW^o{#P>@UhnIpDVt>$cqd<&Rv*}P$>;M74GkfL;QICJ?A*DN`}gnTx-PEkQY;ox z)m8m%+oo77;<_%5lAxI{Z?Ay1G6DLma@Zm$Irlu$s ziwGeCl4S`C67Cm51meje1r6Wx%9Sesw6(QWogI$j1mu=00@!XC{L(b}m1*)uOA8Hn z%T<$Qq3JpwTNVIsSQd|b^5v*q^2L$$l?dPaOp^wmTmjSqNnj^1+24=8YZp#S3y*xC zrLk&`6P*qv2>|=|?f%pXQ}K5SX^8LVC&Yc zLAwxwSS(g{vrsLm?>0?z!$1Qb=kwgnWT*vFmc`V_2=mj^d^IvcXC}ji{(cfZp~4p; zT$kjP^Bn`OnkF*BT3{>C0Bl)U06@`o7J&qzlev$oOO_nHLI|#1yT+wUmk>g5`SN9s z961t5@yct%{o%UYsY(Cg!O_~<3c!O04{%+#>P{<45CMFV%klSYmIU5%r31T6 zlVnE+HHN_-#>R;2IzQgEi(gn4k8`=er<^I_x>LdT79h@A0i}J?Gy(V~pQj0LhLk={ z)fo~d6+ALisTA>eJorC4I!Zd7=IYg}%+1Y_PN$ijo#pP`yTKM%+R7qD2yc<)ecIdG zIeYdj6B85Mym@oo4y)V@i5gbIfAHXGCDd+DwSerXoz?`&cwt7XU?2iLtMC?PNzwy(*R6NOmOesJz85^xpnIn05dZ) z3=a=8Fff3ss_O)MktGW}!gb(Bz*fUx_o-9-t-G6lkB#vPPz1ip<@nv;Ag`Dv%d8dP z=N%pVC3Nq3rV0PqIAny?F3!g7hb}mY|G`0O0QTTddaHC6G9Rxlk_&=HNUMMk02Fz6>le{ z!J6c}4Nn9+j7} puQxh`=f!jl^w+}BA4A{N{|_X2wT_RE(v$!I002ovPDHLkV1lEB%d-Fg literal 0 HcmV?d00001 diff --git a/assets/img/build-ok.png b/assets/img/build-ok.png new file mode 100644 index 0000000000000000000000000000000000000000..ca59686f4b8fde6ae25da98acd00a0d1dd67558e GIT binary patch literal 1839 zcmV+~2hjM5P)dbVG7wVRUJ4ZXi@?ZDjy4H!n3W zF*60>Ig$VX0338hSaefwW^{L9a%BKPWN%_+AVz6&Wp{6KYjYq&Q#En5<2C>Q28c;S zK~!jg)tPT-Tv-{$f9K95ZPKxsfEjmIt%H9sZ30QUZd0*sCSgTVyL44*6=|E!P_@A= z^Fg=DE;Nczu}HHk3tJ^Nfpv)#*-A?Gnwp6VC(}g+@rNtk%*cjcx~3KoIRShu<^jvqhnQ%a2h_2p(&3dVQ#mzzSVm=S_Dw`EzU zD3A=jzA2^bV*nvU&f|R7JK>CX_MaW2VZ>k%d*0`1k=z-aGGw< zCzuf8k>ou}V70*6{p-H7Egv5Dgk%tQTbA|2S`ku8lv1>{wNY1BXNz|2+BN3p<}eI{ zj*brI=H{55p0-6heE6^()85|By?ghVo}SJb+tAQJLqmg|jJdfv#>U22T3SK~fngXJ zhOuT+q}(`Fw%0ZD%x9hh3IB-4_{*Kk7;eCTk8cg|^&MTjJlcbBK~1%nV>=@}SWIy7 zZ@q{L5U!$c{e)pz7KJR8N)ZeO*}i={rfCug1UP^GJZ`s}<>h7DmrA83`+f%w9N@x*3+&ssZ&jRWnwX}UlcSWBY@P})uYWVj@4ppgi{-^! zfR~=>W#r^tKD((I^S|)qmH?;ro+0^fsFq${KOE)w7b1*~M@c3?rb^@BmIa2^$^%Pc zu^0mb11P1qdi5&Xwryi-Y6>YOQc6;(6oz5g*P5nDDwRS?iDg+NlS%v787rkE9*^67 zU%YscqeqVtiA0FSV%)!fAHy(kxm@;)d6Z|-qteEU?Y->ySThHI7G&yQF^tXd+Hfy# zz7XX%-?>a{PXP1DbnNndI2Z0mS01uWDRQSMBAWGn}t{GyQCQ2!MJ|B&ZjT||0 zggbZcFf%hlDwRShWs9s0Ruba$E2Zq@Y10XH-t*F>O8~UCwicWnX`^KO%IBZsjc7ly zzsC?&;QA;mR3|t$+`}j9KE>y%n=u#D!o3{o=Myyno;?#J@j(K^3v2;NX&l^EfuW^E z0BCAz!sqkh_xqWhowbG1BAceUYK?a$Q~RCC(eDL4OSKgsB{T`7gj<;wZ7 zun{xlBb#e@KaoIHfXE08@W4o<{cbPT!*p9sm6xrXyqHTMwx;7%1z07%%M3j_3z<@i z;o)IUo;=CHg9q_=JnY}U-xgB~t(P~zzSil_j@9wHO<&X0)C9oo+qc)nZzE>N^n171 z+ZaTV8R;@@U;K0sfLs5JAkH=%5 z4-E~`+1ZKD=R-B*6_|cco@QXkEl*Cd3+-V)=lL_|s1VO-+A4aKu=*3zt zokPJT%Q=EWp%9@^h=qj(Mn*;$92~?j42Fh=@caD?3=H7$c$l1=T4`Y2n6=8vxAC&N4VSNMBzchGDEqSax44JlA}Tb>aFuQTDvl!jBL1 z@J{dh08G7mi*KL%8dsv15gt&LnddQJ-bnEM{w{`Jh;k(o<*UC6^1-GAqM~>XqNAfD zfAz-7vXi|WY3TO=tX+}ks`hgght780x2{9hszt_kUMu{xg`hw^1o;5e0;o)qg#n@p zj2fU4SC0UC$0Y8Gj`xS32IP0z~>;70E>@;%+HrAMj%Spxk>`&T}nt zuEZ4DgIYh?{K)_?%?-It8UomyF(>r0=*pOGGXUqTD4t87+ceErgb?3gjSa?ZF|_!F zM9S62dgHVEFO=Ag+&U=}W|ZO;0kC`b?#KRr$oS5`mYYH;SOhv#ud3_zu-mn3*V9U= z$M%omc=KE3rcfLNV+fv?uQ~o0YBV%7crD91W?5DQ2$X|gv3PsO+vTS4VR4rVdZ}c9 dH&*_s{||ZwyW{XYHHH8H002ovPDHLkV1ns2d~pB( literal 0 HcmV?d00001 diff --git a/assets/img/icon-build-failed.png b/assets/img/icon-build-failed.png new file mode 100644 index 0000000000000000000000000000000000000000..9dde31bdb83dc2fd4b4dfb3653e9c094d6ac09da GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8wRq zxP?HN@zUM8KR`jz64!_l=c3falFa-(g^iLmL>syAAH dny+8Z#5+xKxuDIOV4y=7JYD@<);T3K0RW9rVOszI literal 0 HcmV?d00001 diff --git a/assets/img/icon-build-running.png b/assets/img/icon-build-running.png new file mode 100644 index 0000000000000000000000000000000000000000..593f00b5dc3891f054d53a2bcb9407fd12df7880 GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8wRq zxP?HN@zUM8KR`jz64!_l=c3falFa-(g^!YKp4bN_inoPMa(Jf2Y27^wwH+YVr)Z$owNa{ajdLBO5q&6wPT=U|%WceWqu& z&VieiM>c1_+A76;IZNtlm@P VcsrUp+kp;X@O1TaS?83{1OQUXVp{+J literal 0 HcmV?d00001