Compare commits

...

14 commits

Author SHA1 Message Date
Dmitry Khomutov 11ef5ef302
Fixed Notice error. Issue #185. 2018-06-04 20:54:33 +07:00
Dmitry Khomutov 361a06a127
Merge branch 'gogs-content-type' 2018-06-04 20:44:01 +07:00
Dmitry Khomutov b54af48bd7
Fixed content type check for Gogs webhook. Issue #185. 2018-06-04 18:52:52 +07:00
Dmitry Khomutov ef4ebe14b4
Merge branch 'codeception-xml' 2018-05-29 18:13:31 +07:00
Dmitry Khomutov 7bc9d1ff12
Improved XML loading for Codeception. Issue #182. 2018-05-28 21:35:33 +07:00
Dmitry Khomutov 541c6ffc3f
Merge branch 'plugins-docs' 2018-05-27 12:56:31 +07:00
Dmitry Khomutov 456e2ace9b
Added information about additional dependencies for some plugins
(Hipchat, Slack and Flowdock).
2018-05-27 12:56:01 +07:00
Dmitry Khomutov c637db899f
Merge pull request #178 from underthecocotree/patch-1
php_code_sniffer not including phpcs.xml standard
2018-05-21 17:53:09 +07:00
Phoebus Apostolidis b13049187e Update php_code_sniffer to ~3.2.0 2018-05-21 10:18:27 +01:00
Phoebus a270c740c3
php_code_sniffer not including phpcs.xml standard
I thought I had the standard path wrong but after updating php_codesniffer from composer it started reading phpcs.xml.

Ref:
https://github.com/squizlabs/PHP_CodeSniffer/issues/1660
2018-05-16 17:17:06 +01:00
Dmitry Khomutov 71ac385bac
Merge pull request #177 from underthecocotree/patch-1
Installing HipChat via composer
2018-05-16 07:37:19 +07:00
Phoebus c2b94a5bf7
Installing HipChat via composer
I was getting the following error:
Class 'HipChat\HipChat' not found

After checking composer.json I saw the `suggest` packages. 

Good to have in the documentation.
2018-05-15 20:43:15 +01:00
Dmitry Khomutov b3b19f5b99
Merge branch 'feature-ci' 2018-05-07 20:47:19 +07:00
Dmitry Khomutov 95577f178a
ci.php-censor.info config fixes. 2018-05-07 20:47:04 +07:00
12 changed files with 220 additions and 147 deletions

View file

@ -1,5 +1,4 @@
build_settings: build_settings:
clone_depth: 1
ignore: ignore:
- vendor - vendor
- tests - tests
@ -14,11 +13,6 @@ test:
- phpunit.xml - phpunit.xml
coverage: true coverage: true
php_mess_detector:
allow_failures: true
rules:
- phpmd.xml
php_code_sniffer: php_code_sniffer:
standard: PSR2 standard: PSR2
encoding: UTF-8 encoding: UTF-8
@ -33,9 +27,6 @@ test:
php_parallel_lint: php_parallel_lint:
allow_failures: true allow_failures: true
php_docblock_checker:
allow_failures: true
security_checker: security_checker:
allow_failures: false allow_failures: false

View file

@ -76,7 +76,7 @@
"codeception/codeception": "~2.3.0", "codeception/codeception": "~2.3.0",
"phpmd/phpmd": "~2.6.0", "phpmd/phpmd": "~2.6.0",
"sebastian/phpcpd": "~2.0.0", "sebastian/phpcpd": "~2.0.0",
"squizlabs/php_codesniffer": "~2.8.0", "squizlabs/php_codesniffer": "~3.2.0",
"block8/php-docblock-checker": "~1.3.0", "block8/php-docblock-checker": "~1.3.0",
"phploc/phploc": "~4.0.0", "phploc/phploc": "~4.0.0",
"jakub-onderka/php-parallel-lint": "~0.9.0", "jakub-onderka/php-parallel-lint": "~0.9.0",

51
composer.lock generated
View file

@ -1,10 +1,10 @@
{ {
"_readme": [ "_readme": [
"This file locks the dependencies of your project to a known state", "This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "6c8facd9ea26fd63006a35d445fac984", "content-hash": "8ed0d649c464752b717de050e04cd313",
"packages": [ "packages": [
{ {
"name": "behat/gherkin", "name": "behat/gherkin",
@ -2959,64 +2959,37 @@
}, },
{ {
"name": "squizlabs/php_codesniffer", "name": "squizlabs/php_codesniffer",
"version": "2.8.1", "version": "3.2.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d" "reference": "4842476c434e375f9d3182ff7b89059583aa8b27"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d", "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4842476c434e375f9d3182ff7b89059583aa8b27",
"reference": "d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d", "reference": "4842476c434e375f9d3182ff7b89059583aa8b27",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-simplexml": "*", "ext-simplexml": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"php": ">=5.1.2" "php": ">=5.4.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "~4.0" "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
}, },
"bin": [ "bin": [
"scripts/phpcs", "bin/phpcs",
"scripts/phpcbf" "bin/phpcbf"
], ],
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "2.x-dev" "dev-master": "3.x-dev"
} }
}, },
"autoload": {
"classmap": [
"CodeSniffer.php",
"CodeSniffer/CLI.php",
"CodeSniffer/Exception.php",
"CodeSniffer/File.php",
"CodeSniffer/Fixer.php",
"CodeSniffer/Report.php",
"CodeSniffer/Reporting.php",
"CodeSniffer/Sniff.php",
"CodeSniffer/Tokens.php",
"CodeSniffer/Reports/",
"CodeSniffer/Tokenizers/",
"CodeSniffer/DocGenerators/",
"CodeSniffer/Standards/AbstractPatternSniff.php",
"CodeSniffer/Standards/AbstractScopeSniff.php",
"CodeSniffer/Standards/AbstractVariableSniff.php",
"CodeSniffer/Standards/IncorrectPatternException.php",
"CodeSniffer/Standards/Generic/Sniffs/",
"CodeSniffer/Standards/MySource/Sniffs/",
"CodeSniffer/Standards/PEAR/Sniffs/",
"CodeSniffer/Standards/PSR1/Sniffs/",
"CodeSniffer/Standards/PSR2/Sniffs/",
"CodeSniffer/Standards/Squiz/Sniffs/",
"CodeSniffer/Standards/Zend/Sniffs/"
]
},
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"BSD-3-Clause" "BSD-3-Clause"
@ -3033,7 +3006,7 @@
"phpcs", "phpcs",
"standards" "standards"
], ],
"time": "2017-03-01T22:17:45+00:00" "time": "2018-02-20T21:35:23+00:00"
}, },
{ {
"name": "swiftmailer/swiftmailer", "name": "swiftmailer/swiftmailer",

View file

@ -78,7 +78,7 @@ Plugins
* [Campfire](plugins/campfire.md) - `campfire` * [Campfire](plugins/campfire.md) - `campfire`
* [Email](plugins/email.md) - `email` * [Email](plugins/email.md) - `email`
* FlowDock - `flowdock_notify` * [FlowDock](plugins/flowdock_notify.md) - `flowdock_notify`
* [HipChat](plugins/hipchat_notify.md) - `hipchat_notify` * [HipChat](plugins/hipchat_notify.md) - `hipchat_notify`
* [IRC](plugins/irc.md) - `irc` * [IRC](plugins/irc.md) - `irc`
* [Slack](plugins/slack_notify.md) - `slack_notify` * [Slack](plugins/slack_notify.md) - `slack_notify`

View file

@ -0,0 +1,14 @@
Plugin FlowdockNotify
=====================
This plugin joins a [Flowdock](https://www.flowdock.com/) room and sends a user-defined message, for example a
"Build Succeeded" message.
Installation
------------
The plugin depends on `mremi/flowdock` library. To use FlowdockNotify plugin you should install dependency:
```
composer require "mremi/flowdock"
```

View file

@ -1,9 +1,18 @@
Plugin Hipchat Notify Plugin HipchatNotify
===================== =====================
This plugin joins a [HipChat](https://www.hipchat.com/) room and sends a user-defined message, for example a This plugin joins a [HipChat](https://www.hipchat.com/) room and sends a user-defined message, for example a
"Build Succeeded" message. "Build Succeeded" message.
Installation
------------
The plugin depends on `hipchat/hipchat-php` library. To use HipchatNotify plugin you should install dependency:
```
composer require "hipchat/hipchat-php"
```
Configuration Configuration
------------- -------------

View file

@ -1,9 +1,18 @@
Plugin Slack Notify Plugin SlackNotify
=================== ===================
This plugin joins a [Slack](https://www.slack.com/) room and sends a user-defined message, for example a "Build This plugin joins a [Slack](https://www.slack.com/) room and sends a user-defined message, for example a "Build
Succeeded" message. Succeeded" message.
Installation
------------
The plugin depends on `maknz/slack` library. To use SlackNotify plugin you should install dependency:
```
composer require "maknz/slack"
```
Configuration Configuration
------------- -------------

View file

@ -592,11 +592,11 @@ class WebhookController extends Controller
} }
/** /**
* Called by Gogs Webhooks:
*
* @param string $projectId * @param string $projectId
* *
* @return array * @return array
*
* @throws Exception
*/ */
public function gogs($projectId) public function gogs($projectId)
{ {
@ -605,15 +605,17 @@ class WebhookController extends Controller
Project::TYPE_GIT, Project::TYPE_GIT,
]); ]);
switch ($_SERVER['CONTENT_TYPE']) { $contentType = !empty($_SERVER['CONTENT_TYPE'])
case 'application/json': ? $_SERVER['CONTENT_TYPE']
$payload = json_decode(file_get_contents('php://input'), true); : null;
break;
switch ($contentType) {
case 'application/x-www-form-urlencoded': case 'application/x-www-form-urlencoded':
$payload = json_decode($this->getParam('payload'), true); $payload = json_decode($this->getParam('payload'), true);
break; break;
case 'application/json':
default: default:
return ['status' => 'failed', 'error' => 'Content type not supported.', 'responseCode' => 401]; $payload = json_decode(file_get_contents('php://input'), true);
} }
// Handle Push web hooks: // Handle Push web hooks:

85
src/Helper/Xml.php Normal file
View file

@ -0,0 +1,85 @@
<?php
namespace PHPCensor\Helper;
class XmlUtf8CleanFilter extends \php_user_filter
{
const PATTERN = '/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u';
/**
* @param resource $in
* @param resource $out
* @param int $consumed
* @param bool $closing
*
* @return int
*/
function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
$bucket->data = preg_replace(self::PATTERN, '', $bucket->data);
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
class Xml
{
/**
* @param $filePath
*
* @return null|\SimpleXMLElement
*/
public static function loadFromFile($filePath)
{
stream_filter_register('xml_utf8_clean', 'PHPCensor\Helper\XmlUtf8CleanFilter');
try {
$xml = simplexml_load_file('php://filter/read=xml_utf8_clean/resource=' . $filePath);
} catch (\Exception $ex) {
$xml = null;
} catch (\Throwable $ex) { // since php7
$xml = null;
}
if (!$xml) {
// from https://stackoverflow.com/questions/7766455/how-to-handle-invalid-unicode-with-simplexml/8092672#8092672
$oldUse = libxml_use_internal_errors(true);
libxml_clear_errors();
$dom = new \DOMDocument("1.0", "UTF-8");
$dom->strictErrorChecking = false;
$dom->validateOnParse = false;
$dom->recover = true;
$dom->loadXML(strtr(
file_get_contents($filePath),
['&quot;' => "'"] // &quot; in attribute names may mislead the parser
));
/** @var \LibXMLError $xmlError */
$xmlError = libxml_get_last_error();
if ($xmlError) {
$warning = sprintf('L%s C%s: %s', $xmlError->line, $xmlError->column, $xmlError->message);
print 'WARNING: ignored errors while reading phpunit result, '.$warning."\n";
}
if (!$dom->hasChildNodes()) {
new \SimpleXMLElement('<empty/>');
}
$xml = simplexml_import_dom($dom);
libxml_clear_errors();
libxml_use_internal_errors($oldUse);
}
return $xml;
}
}

View file

@ -145,8 +145,7 @@ class Codeception extends Plugin implements ZeroConfigPluginInterface
} }
} }
$xml = file_get_contents($outputPath . 'report.xml', false); $parser = new Parser($this->builder, ($outputPath . 'report.xml'));
$parser = new Parser($this->builder, $xml);
$output = $parser->parse(); $output = $parser->parse();
$meta = [ $meta = [

View file

@ -2,6 +2,8 @@
namespace PHPCensor\Plugin\Util; namespace PHPCensor\Plugin\Util;
use PHPCensor\Helper\Xml;
/** /**
* Class PhpUnitResultJunit parses the results for the PhpUnitV2 plugin * Class PhpUnitResultJunit parses the results for the PhpUnitV2 plugin
* *
@ -24,11 +26,11 @@ class PhpUnitResultJunit extends PhpUnitResult
$suites = $this->loadResultFile(); $suites = $this->loadResultFile();
foreach ($suites->xpath('//testcase') as $testCase) { if ($suites) {
$this->parseTestcase($testCase); foreach ($suites->xpath('//testcase') as $testCase) {
$this->parseTestcase($testCase);
}
} }
$suites['failures'];
$suites['errors'];
return $this; return $this;
} }
@ -139,44 +141,7 @@ class PhpUnitResultJunit extends PhpUnitResult
return new \SimpleXMLElement('<empty/>'); // new empty element return new \SimpleXMLElement('<empty/>'); // new empty element
} }
try { return Xml::loadFromFile($this->outputFile);
$suites = simplexml_load_file($this->outputFile);
} catch (\Exception $ex) {
$suites = null;
} catch (\Throwable $ex) { // since php7
$suites = null;
}
if (!$suites) {
// from https://stackoverflow.com/questions/7766455/how-to-handle-invalid-unicode-with-simplexml/8092672#8092672
$oldUse = libxml_use_internal_errors(true);
libxml_clear_errors();
$dom = new \DOMDocument("1.0", "UTF-8");
$dom->strictErrorChecking = false;
$dom->validateOnParse = false;
$dom->recover = true;
$dom->loadXML(strtr(
file_get_contents($this->outputFile),
array('&quot;' => "'") // &quot; in attribute names may mislead the parser
));
/**
* @var \LibXMLError
*/
$xmlError = libxml_get_last_error();
if ($xmlError) {
$warning = sprintf('L%s C%s: %s', $xmlError->line, $xmlError->column, $xmlError->message);
print 'WARNING: ignored errors while reading phpunit result, '.$warning."\n";
}
if (!$dom->hasChildNodes()) {
$this->internalProblem('xml file with no content');
}
$suites = simplexml_import_dom($dom);
libxml_clear_errors();
libxml_use_internal_errors($oldUse);
}
return $suites;
} }
/** /**
@ -185,7 +150,5 @@ class PhpUnitResultJunit extends PhpUnitResult
private function internalProblem($description) private function internalProblem($description)
{ {
throw new \RuntimeException($description); throw new \RuntimeException($description);
// alternative to error throwing: append to $this->errors
} }
} }

View file

@ -3,6 +3,7 @@
namespace PHPCensor\Plugin\Util\TestResultParsers; namespace PHPCensor\Plugin\Util\TestResultParsers;
use PHPCensor\Builder; use PHPCensor\Builder;
use PHPCensor\Helper\Xml;
/** /**
* Class Codeception * Class Codeception
@ -11,23 +12,49 @@ use PHPCensor\Builder;
*/ */
class Codeception implements ParserInterface class Codeception implements ParserInterface
{ {
/**
* @var Builder
*/
protected $builder; protected $builder;
protected $resultsXml;
/**
* @var string
*/
protected $xmlPath;
/**
* @var array
*/
protected $results; protected $results;
protected $totalTests;
protected $totalTimeTaken; /**
protected $totalFailures; * @var int
protected $totalErrors; */
protected $totalTests = 0;
/**
* @var int
*/
protected $totalTimeTaken = 0;
/**
* @var int
*/
protected $totalFailures = 0;
/**
* @var int
*/
protected $totalErrors = 0;
/** /**
* @param Builder $builder * @param Builder $builder
* @param $resultsXml * @param string $xmlPath
*/ */
public function __construct(Builder $builder, $resultsXml) public function __construct(Builder $builder, $xmlPath)
{ {
$this->builder = $builder; $this->builder = $builder;
$this->resultsXml = $resultsXml; $this->xmlPath = $xmlPath;
$this->totalTests = 0;
} }
/** /**
@ -36,42 +63,43 @@ class Codeception implements ParserInterface
public function parse() public function parse()
{ {
$rtn = []; $rtn = [];
$this->results = new \SimpleXMLElement($this->resultsXml); $this->results = Xml::loadFromFile($this->xmlPath);
// calculate total results if ($this->results) {
foreach ($this->results->testsuite as $testSuite) { foreach ($this->results->testsuite as $testSuite) {
$this->totalTests += (int)$testSuite['tests']; $this->totalTests += (int)$testSuite['tests'];
$this->totalTimeTaken += (float)$testSuite['time']; $this->totalTimeTaken += (float)$testSuite['time'];
$this->totalFailures += (int)$testSuite['failures']; $this->totalFailures += (int)$testSuite['failures'];
$this->totalErrors += (int)$testSuite['errors']; $this->totalErrors += (int)$testSuite['errors'];
foreach ($testSuite->testcase as $testCase) { foreach ($testSuite->testcase as $testCase) {
$testResult = [ $testResult = [
'suite' => (string)$testSuite['name'], 'suite' => (string)$testSuite['name'],
'file' => str_replace($this->builder->buildPath, '/', (string) $testCase['file']), 'file' => str_replace($this->builder->buildPath, '/', (string) $testCase['file']),
'name' => (string)$testCase['name'], 'name' => (string)$testCase['name'],
'feature' => (string)$testCase['feature'], 'feature' => (string)$testCase['feature'],
'assertions' => (int)$testCase['assertions'], 'assertions' => (int)$testCase['assertions'],
'time' => (float)$testCase['time'] 'time' => (float)$testCase['time']
]; ];
if (isset($testCase['class'])) { if (isset($testCase['class'])) {
$testResult['class'] = (string) $testCase['class']; $testResult['class'] = (string) $testCase['class'];
}
// PHPUnit testcases does not have feature field. Use class::method instead
if (!$testResult['feature']) {
$testResult['feature'] = sprintf('%s::%s', $testResult['class'], $testResult['name']);
}
if (isset($testCase->failure) || isset($testCase->error)) {
$testResult['pass'] = false;
$testResult['message'] = isset($testCase->failure) ? (string)$testCase->failure : (string)$testCase->error;
} else {
$testResult['pass'] = true;
}
$rtn[] = $testResult;
} }
// PHPUnit testcases does not have feature field. Use class::method instead
if (!$testResult['feature']) {
$testResult['feature'] = sprintf('%s::%s', $testResult['class'], $testResult['name']);
}
if (isset($testCase->failure) || isset($testCase->error)) {
$testResult['pass'] = false;
$testResult['message'] = isset($testCase->failure) ? (string)$testCase->failure : (string)$testCase->error;
} else {
$testResult['pass'] = true;
}
$rtn[] = $testResult;
} }
} }