Page MenuHomePhorge

D3289.1775402034.diff
No OneTemporary

Authored By
Unknown
Size
9 KB
Referenced Files
None
Subscribers
None

D3289.1775402034.diff

diff --git a/.arcconfig b/.arcconfig
--- a/.arcconfig
+++ b/.arcconfig
@@ -1,3 +1,4 @@
{
- "phabricator.uri": "https://git.kolab.org"
+ "phabricator.uri": "https://git.kolab.org",
+ "load": ["phabricator/arc-phpstan"]
}
diff --git a/.arclint b/.arclint
new file mode 100644
--- /dev/null
+++ b/.arclint
@@ -0,0 +1,21 @@
+{
+ "linters": {
+ "php": {
+ "type": "php"
+ },
+ "phpcs": {
+ "type": "phpcs",
+ "bin": "src/vendor/bin/phpcs",
+ "include": "(\\.php$)",
+ "exclude": "(^phabricator/)"
+ },
+ "phpstan": {
+ "type": "phpstan",
+ "include": "(\\.php$)",
+ "exclude": "(^phabricator/)",
+ "config": "src/phpstan.neon",
+ "bin": "src/vendor/bin/phpstan",
+ "level": "6"
+ }
+ }
+}
diff --git a/phabricator/arc-phpstan/__phutil_library_init__.php b/phabricator/arc-phpstan/__phutil_library_init__.php
new file mode 100755
--- /dev/null
+++ b/phabricator/arc-phpstan/__phutil_library_init__.php
@@ -0,0 +1,18 @@
+<?php
+/*
+ Copyright 2017-present Appsinet. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+phutil_register_library('phpstan', __FILE__);
diff --git a/phabricator/arc-phpstan/__phutil_library_map__.php b/phabricator/arc-phpstan/__phutil_library_map__.php
new file mode 100755
--- /dev/null
+++ b/phabricator/arc-phpstan/__phutil_library_map__.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * This file is automatically generated. Use 'arc liberate' to rebuild it.
+ *
+ * @generated
+ * @phutil-library-version 2
+ */
+phutil_register_library_map(array(
+ '__library_version__' => 2,
+ 'class' => array(
+ 'PhpstanLinter' => 'lint/linter/PhpstanLinter.php',
+ ),
+ 'function' => array(),
+ 'xmap' => array(
+ 'PhpstanLinter' => 'ArcanistExternalLinter',
+ ),
+));
diff --git a/phabricator/arc-phpstan/lint/linter/PhpstanLinter.php b/phabricator/arc-phpstan/lint/linter/PhpstanLinter.php
new file mode 100755
--- /dev/null
+++ b/phabricator/arc-phpstan/lint/linter/PhpstanLinter.php
@@ -0,0 +1,242 @@
+<?php
+/**
+ * @copyright Copyright 2017-present Appsinet. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+/** Uses phpstan to lint php files */
+final class PhpstanLinter extends ArcanistExternalLinter
+{
+
+ /**
+ * @var string Config file path
+ */
+ private $configFile = null;
+
+ /**
+ * @var string Rule level
+ */
+ private $level = null;
+
+ /**
+ * @var string Autoload file path
+ */
+ private $autoloadFile = null;
+
+ public function getInfoName()
+ {
+ return 'phpstan';
+ }
+
+ public function getInfoURI()
+ {
+ return '';
+ }
+
+ public function getInfoDescription()
+ {
+ return pht('Use phpstan for processing specified files.');
+ }
+
+ public function getLinterConfigurationName()
+ {
+ return 'phpstan';
+ }
+
+ public function getDefaultBinary()
+ {
+ return 'phpstan';
+ }
+
+ public function getInstallInstructions()
+ {
+ return pht('Install phpstan following the official guide at https://github.com/phpstan/phpstan#installation');
+ }
+
+ public function shouldExpectCommandErrors()
+ {
+ return true;
+ }
+
+ public function getVersion()
+ {
+ list($stdout) = execx('%C --version', $this->getExecutableCommand());
+
+ $matches = array();
+ $regex = '/(?P<version>\d+\.\d+\.\d+)/';
+ if (preg_match($regex, $stdout, $matches)) {
+ return $matches['version'];
+ } else {
+ return false;
+ }
+ }
+
+ protected function getMandatoryFlags()
+ {
+ $flags = array(
+ 'analyse',
+ '--no-progress',
+ '--error-format=checkstyle',
+ '--memory-limit=1G'
+ );
+ if (null !== $this->configFile) {
+ array_push($flags, '-c', $this->configFile);
+ }
+ if (null !== $this->level) {
+ array_push($flags, '-l', $this->level);
+ }
+ if (null !== $this->autoloadFile) {
+ array_push($flags, '-a', $this->autoloadFile);
+ }
+
+ return $flags;
+ }
+
+ public function getLinterConfigurationOptions()
+ {
+ $options = array(
+ 'config' => array(
+ 'type' => 'optional string',
+ 'help' => pht(
+ 'The path to your phpstan.neon file. Will be provided as -c <path> to phpstan.'
+ ),
+ ),
+ 'level' => array(
+ 'type' => 'optional string',
+ 'help' => pht(
+ 'Rule level used (0 loosest - max strictest). Will be provided as -l <level> to phpstan.'
+ ),
+ ),
+ 'autoload' => array(
+ 'type' => 'optional string',
+ 'help' => pht(
+ 'The path to the auto load file. Will be provided as -a <autoload_file> to phpstan.'),
+ ),
+ );
+ return $options + parent::getLinterConfigurationOptions();
+ }
+
+ public function setLinterConfigurationValue($key, $value)
+ {
+ switch ($key) {
+ case 'config':
+ $this->configFile = $value;
+ return;
+ case 'level':
+ $this->level = $value;
+ return;
+ case 'autoload':
+ $this->autoloadFile = $value;
+ return;
+ default:
+ parent::setLinterConfigurationValue($key, $value);
+ return;
+ }
+ }
+
+ protected function getDefaultMessageSeverity($code)
+ {
+ return ArcanistLintSeverity::SEVERITY_WARNING;
+ }
+
+ protected function parseLinterOutput($path, $err, $stdout, $stderr)
+ {
+ $result = array();
+ if (!empty($stdout)) {
+ $stdout = substr($stdout, strpos($stdout, '<?xml'));
+ $checkstyleOutpout = new SimpleXMLElement($stdout);
+ $errors = $checkstyleOutpout->xpath('//file/error');
+ foreach($errors as $error) {
+ $violation = $this->parseViolation($error);
+ $violation['path'] = $path;
+ $result[] = ArcanistLintMessage::newFromDictionary($violation);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Checkstyle returns output of the form
+ *
+ * <checkstyle>
+ * <file name="${sPath}">
+ * <error line="12" column="10" severity="${sSeverity}" message="${sMessage}" source="${sSource}">
+ * ...
+ * </file>
+ * </checkstyle>
+ *
+ * Of this, we need to extract
+ * - Line
+ * - Column
+ * - Severity
+ * - Message
+ * - Source (name)
+ *
+ * @param SimpleXMLElement $violation The XML Entity containing the issue
+ *
+ * @return array of the form
+ * [
+ * 'line' => {int},
+ * 'column' => {int},
+ * 'severity' => {string},
+ * 'message' => {string}
+ * ]
+ */
+ private function parseViolation(SimpleXMLElement $violation)
+ {
+ return array(
+ 'code' => $this->getLinterName(),
+ 'name' => (string)$violation['message'],
+ 'line' => (int)$violation['line'],
+ 'char' => (int)$violation['column'],
+ 'severity' => $this->getMatchSeverity((string)$violation['severity']),
+ 'description' => (string)$violation['message']
+ );
+ }
+
+ /**
+ * @return string Linter name
+ */
+ public function getLinterName()
+ {
+ return 'phpstan';
+ }
+
+ /**
+ * Map the regex matching groups to a message severity. We look for either
+ * a nonempty severity name group like 'error', or a group called 'severity'
+ * with a valid name.
+ *
+ * @param string $severity_name dict Captured groups from regex.
+ *
+ * @return string @{class:ArcanistLintSeverity} constant.
+ *
+ * @task parse
+ */
+ private function getMatchSeverity($severity_name)
+ {
+ $map = array(
+ 'error' => ArcanistLintSeverity::SEVERITY_ERROR,
+ 'warning' => ArcanistLintSeverity::SEVERITY_WARNING,
+ 'info' => ArcanistLintSeverity::SEVERITY_ADVICE,
+ );
+ foreach ($map as $name => $severity) {
+ if ($severity_name == $name) {
+ return $severity;
+ }
+ }
+ return ArcanistLintSeverity::SEVERITY_ERROR;
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 5, 3:13 PM (15 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18820870
Default Alt Text
D3289.1775402034.diff (9 KB)

Event Timeline