Compare commits

..

1 Commits

Author SHA1 Message Date
James
eb81b0e965 didnt work but useful example 2019-09-22 16:27:31 +01:00
8 changed files with 150 additions and 284 deletions

View File

@ -1,19 +1 @@
Post PHPUnit test results to Gitea
Enable in phpunit.xml with
```plain
<phpunit ... printerClass="JHodges\GiteaBotPHPUnit\ResultPrinter">
<php>
<env name="GiteaUrl" value="https://try.gitea.io/api/v1/"/>
<env name="GiteaUser" value="bot"/>
<!--env name="GiteaPass" value="xxx"/--> <!--probably set this on the machine env-->
<env name="GiteaRepoUser" value="bobemoe"/>
<env name="GiteaRepo" value="test"/>
</php>
<logging>
<log type="junit" target="/tmp/logfile.xml"/>
</logging>
```

View File

@ -8,7 +8,7 @@
}
],
"require": {
"jhodges/giteabot": "dev-master"
"jhodges/giteabot": "~1.2.0"
},
"autoload": {
"psr-4": {

19
src/Extention.php Normal file
View File

@ -0,0 +1,19 @@
<?php declare(strict_types=1);
namespace JHodges\GiteaBitPHPUnit;
use PHPUnit\Runner\BeforeFirstTestHook;
use PHPUnit\Runner\AfterLastTestHook;
final class Extension implements BeforeFirstTestHook, AfterLastTestHook{
public function executeBeforeFirstTest(): void
{
// called before the first test is being run
echo "AAAAAA";
}
public function executeAfterLastTest(): void
{
echo "ZZZZZZZ";
// called after the last test has been run
}
}

57
src/Listener.php Normal file
View File

@ -0,0 +1,57 @@
<?php
namespace JHodges\GiteaBotPHPUnit;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\Test as PHPUnit_Framework_Test;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\AssertionFailedError as PHPUnit_Framework_AssertionFailedError;
use PHPUnit\Framework\TestSuite as PHPUnit_Framework_TestSuite;
use PHPUnit\Framework\Warning;
use Exception;
class Listener implements TestListener{
private $stack=[];
public function addWarning(Test $test, Warning $e, $time){
die("wrank");
print_r($test->getName());
}
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time){
die("err");
print_r($test->getName());
}
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time){
$name=get_class($test).'::'.$test->getName();
$message=$e->getMessage();
echo("##### $name\n$message\n");
}
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time){}
public function addRiskyTest(PHPUnit_Framework_Test $test, Exception $e, $time){}
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time){}
public function startTest(PHPUnit_Framework_Test $test){}
public function endTest(PHPUnit_Framework_Test $test, $time){
print_r( $test->getActualOutput());
}
public function startTestSuite(PHPUnit_Framework_TestSuite $suite){
$this->stack[$suite->getName()]='yes';
}
public function endTestSuite(PHPUnit_Framework_TestSuite $suite){
unset($this->stack[$suite->getName()]);
if(count($this->stack)==0){
echo "\n\nALLDONE\n\n";
}
}
}

View File

@ -1,160 +0,0 @@
<?php
namespace JHodges\GiteaBotPHPUnit;
use \JHodges\GiteaBot\Client;
/**
* creates a new issue for each failed test
* if it already exists then report is added as a comment
* if exact error exists as body or comment then just link to it instead of posting again
* if it passes then the issue is closed
*/
final class PostFailedTests{
private $repo=null;
private $xml=null;
function __construct($xml_path){
$this->xml = simplexml_load_file($xml_path);
}
public function post($url, $user, $pass, $repoUser, $repo){
if(!$url) return;
// open connection and repo
$client=new Client($url, $user, $pass, true);
$this->repo=$client->getRepo($repoUser, $repo);
$this->process($this->xml);
}
private function process($item){
if(isset($item->testcase)){
foreach($item->testcase as $testcase) {
$att = current($testcase->attributes());
$name=$att['class'].'::'.$att['name'];
$fail=false;
foreach($testcase as $k=>$v){
$this->fail($name,$att,$k,$v);
$fail=true;
}
if(!$fail){
$this->success($name,$att);
}
}
}
if(isset($item->testsuite)){
foreach($item->testsuite as $testsuite) {
$this->process($testsuite);
}
}
}
private function success($name,$att){
$issue=$this->repo->getIssues(['q' => $name])[0]??null;
if($issue){
$issue->state='closed';
$issue->save();
}
}
private function fail($name,$att,$error,$message){
//stick the error type into the atts array
$att['result']=$error;
//trim the message
$message=trim($message);
// get any existing issue
$issue=$this->repo->getIssues(['q' => $name])[0]??null;
// if existing issue.
if($issue){
// are there any instructions in comments?
$quiet=$silent=false;
foreach($issue->getComments() as $comment){
if( stripos('@bot quiet',$comment->body)!==false ){
$quiet=true;
$silent=false;
}
if( stripos('@bot silent',$comment->body)!==false ){
$silent=true;
$quiet=true;
}
if( stripos('@bot normal',$comment->body)!==false ){
$silent=false;
$quiet=false;
}
}
if($silent){return;}
//is the error the same?
if( $this->doesMessageMatch($issue->body,$message,$att) ){
if($quiet){return;}
$issue->addComment("Failed again. Same errors as [above]($issue->html_url#issue-{$issue->id})");
return;
}else{
foreach($issue->getComments() as $comment){
if( $this->doesMessageMatch($comment->body,$message,$att) ){
if($quiet){return;}
$issue->addComment("Failed again. Same errors as [above]($issue->html_url#issuecomment-{$comment->id})");
return;
}
}
}
}
//so its a new issue or changed error, lets upload screenshot and compose the body
$issueBody='';
if(file_exists("/tmp/$name.png")){
$data=$this->repo->addReleaseAttachment(1,"/tmp/$name.png");
$url=$data->browser_download_url;
$issueBody.="\n![]($url)\n";
unlink("/tmp/$name.png");
}
if($message) $issueBody.="```plain\n$message\n```\n";
foreach($att as $k=>$v){
$issueBody.=" * $k = $v\n";
}
//post the body
if($issue){
$issue->addComment($issueBody);
}else{
$issue=$this->repo->createIssue([
'title'=>'Failed test '.$name,
'body'=>$issueBody
]);
}
}
private function doesMessageMatch($body,$message,$att){
// extract the old message
preg_match('#```plain\n(.*)\n```#s',$body,$match);
$messageOld=$match[1]??'';
// return false if not the same
if( $message != $messageOld ){
return false;
}
// extract the old atts
$attOld=[];
preg_match_all('# \* (.*?) = (.*)#',$body,$m);
foreach($m[0]??[] as $k=>$v){
$attOld[$m[1][$k]]=$m[2][$k];
}
// make sure all current attributes (except time) are the same as old
// return false on first mis-match
foreach($att as $k=>$v){
if($k=='time') continue;
if(($attOld[$k]??null) != $v){
return false;
}
}
// all matches, error message is the same
return true;
}
}

View File

@ -1,80 +0,0 @@
<?php
namespace JHodges\GiteaBotPHPUnit;
use \JHodges\GiteaBot\Client;
final class PostFullReport{
private $report;
private $level=0;
private $failCount=0;
function __construct($xml_path){
$this->xml = simplexml_load_file($xml_path);
}
public function post($url, $user, $pass, $repoUser, $repo){
if(!$url) return;
// open connection and repo
$this->client=new Client($url, $user, $pass);
$this->repo=$this->client->getRepo($repoUser, $repo);
$this->process($this->xml); //process xml and upload screenshots
// create the issue
if(trim($this->report)){
$issue=$this->repo->createIssue([
'title'=>'Test Results',
'body'=>$this->report
]);
}
}
public function getFailCount(){
return $this->failCount;
}
private function process($item){
$this->level++;
if(isset($item->testcase)){
foreach($item->testcase as $testcase) {
$att=$testcase->attributes();
$failmsg='';
foreach($testcase as $k=>$v){
$failmsg="(**$k**)\n";
if(trim($v)) $failmsg.="```plain\n$v\n```\n";
}
if($failmsg){
$this->failCount++;
$this->report.=" * [ ] {$att->name[0]} $failmsg\n";
}else{
$this->report.=" * [x] {$att->name[0]}\n";
}
$name=$testcase->attributes()->class[0].'::'.$testcase->attributes()->name[0];
if(file_exists("/tmp/$name.png")){
$data=$this->repo->addReleaseAttachment(1,"/tmp/$name.png");
$url=$data->browser_download_url;
$img="\n![]($url)\n";
unlink("/tmp/$name.png");
$this->report.="$img\n";
}
}
}
if(isset($item->testsuite)){
foreach($item->testsuite as $testsuite) {
$att=$testsuite->attributes();
$this->report.=str_repeat('#',$this->level)." {$att->name[0]}\n".
"tests: {$att->tests[0]}".
", assertions: {$att->assertions[0]}".
", errors: {$att->errors[0]}".
", failures: {$att->failures[0]}".
", skipped: {$att->skipped[0]}".
", time: {$att->time[0]}".
"\n";
$this->process($testsuite);
}
}
$this->level--;
}
}

48
src/Poster.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace JHodges\GiteaBotPHPUnit;
use \JHodges\GiteaBot\Client;
final class Poster{
private $report;
function __construct($testdox_path,$xml_path){
$testdox=file_get_contents($testdox_path);
$testdox=preg_replace('# \[#',' * [',$testdox);
$this->report.=$testdox;
$xml = simplexml_load_file($xml_path);
$this->process($xml);
}
public function post($url, $user, $pass, $repoUser, $repo){
// open connection and repo
$client=new Client($url, $user, $pass, $repoUser, $repo);
$repo=$client->getRepo($repoUser, $repo);
// create the issue
$issue=$repo->createIssue([
'title'=>'Test Results',
'body'=>$this->report
]);
}
private function process($item){
if(isset($item->testcase)){
foreach($item->testcase as $testcase) {
foreach($testcase as $k=>$v){
$this->report.="\n```plain\n".print_r($testcase,true)."\n```";
}
}
}
if(isset($item->testsuite)){
foreach($item->testsuite as $testsuite) {
$this->process($testsuite);
}
}
}
}

View File

@ -1,34 +1,34 @@
<?php
namespace JHodges\GiteaBotPHPUnit;
class ResultPrinter extends \PHPUnit\TextUI\ResultPrinter{
class ResultPrinter extends \PHPUnit\TextUI\ResultPrinter
{
public function __construct($out = null, $verbose = false, $colors = self::COLOR_DEFAULT, $debug = false, $numberOfColumns = 80){
parent::__construct($out, $verbose, $colors , $debug , $numberOfColumns);
}
public function printResult(\PHPUnit\Framework\TestResult $result){
parent::printResult($result);
$poster=new \JHodges\GiteaBotPHPUnit\PostFailedTests('/tmp/logfile.xml');
$poster->post(
public function printResult(\PHPUnit\Framework\TestResult $result)
{
$poster=new \JHodges\GiteaBotPHPUnit\Poster('/tmp/testdox.txt','/tmp/logfile.xml');
$poster->post(
getenv('GiteaUrl'),
getenv('GiteaUser'),
getenv('GiteaPass'),
getenv('GiteaRepoUser'),
getenv('GiteaRepo')
);
);
}
protected function printHeader(){
parent::printHeader();
protected function printHeader()
{
}
public function messageProcessor(array $record){
parent::messageProcessor($record);
public function messageProcessor(array $record)
{
}
public function suiteNameProcessor(array $record){
parent::suiteNameProcessor($record);
public function suiteNameProcessor(array $record)
{
}
}