Page MenuHomePhabricator

D10738.id26566.diff
No OneTemporary

D10738.id26566.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -154,6 +154,8 @@
'ArcanistRepositoryAPIMiscTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIMiscTestCase.php',
'ArcanistRepositoryAPIStateTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php',
'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php',
+ 'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
+ 'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
'ArcanistRubyLinterTestCase' => 'lint/linter/__tests__/ArcanistRubyLinterTestCase.php',
'ArcanistScriptAndRegexLinter' => 'lint/linter/ArcanistScriptAndRegexLinter.php',
@@ -335,6 +337,8 @@
'ArcanistRepositoryAPIMiscTestCase' => 'ArcanistTestCase',
'ArcanistRepositoryAPIStateTestCase' => 'ArcanistTestCase',
'ArcanistRevertWorkflow' => 'ArcanistWorkflow',
+ 'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
+ 'ArcanistRuboCopLinterTestCase' => 'ArcanistArcanistLinterTestCase',
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
'ArcanistRubyLinterTestCase' => 'ArcanistArcanistLinterTestCase',
'ArcanistScriptAndRegexLinter' => 'ArcanistLinter',
diff --git a/src/lint/linter/ArcanistRuboCopLinter.php b/src/lint/linter/ArcanistRuboCopLinter.php
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/ArcanistRuboCopLinter.php
@@ -0,0 +1,127 @@
+<?php
+
+final class ArcanistRuboCopLinter extends ArcanistExternalLinter {
+
+ private $config;
+
+ public function getInfoName() {
+ return 'RuboCop';
+ }
+
+ public function getInfoURI() {
+ return 'http://batsov.com/rubocop';
+ }
+
+ public function getInfoDescription() {
+ return pht(
+ 'RuboCop is a Ruby static code analyzer, based on the community Ruby '.
+ 'style guide.');
+ }
+
+ public function getLinterName() {
+ return 'RuboCop';
+ }
+
+ public function getLinterConfigurationName() {
+ return 'rubocop';
+ }
+
+ public function getDefaultBinary() {
+ return 'rubocop';
+ }
+
+ public function getVersion() {
+ list($stdout) = execx('%C --version', $this->getExecutableCommand());
+
+ $matches = array();
+ if (preg_match('/^(?P<version>\d+\.\d+\.\d+)$/', $stdout, $matches)) {
+ return $matches['version'];
+ } else {
+ return false;
+ }
+ }
+
+ public function getInstallInstructions() {
+ return pht('Install RuboCop using `gem install rubocop`.');
+ }
+
+ public function shouldExpectCommandErrors() {
+ return true;
+ }
+
+ public function supportsReadDataFromStdin() {
+ return false;
+ }
+
+ protected function getMandatoryFlags() {
+ $options = array(
+ '--format=json',
+ '--force-exclusion',
+ '--no-color',
+ );
+
+ if ($this->config) {
+ $options[] = '--config='.$this->config;
+ }
+
+ return $options;
+ }
+
+ public function getLinterConfigurationOptions() {
+ $options = array(
+ 'rubocop.config' => array(
+ 'type' => 'optional string',
+ 'help' => pht('A custom configuration file.'),
+ ),
+ );
+
+ return $options + parent::getLinterConfigurationOptions();
+ }
+
+ public function setLinterConfigurationValue($key, $value) {
+ switch ($key) {
+ case 'rubocop.config':
+ $this->config = $value;
+ return;
+ }
+
+ return parent::setLinterConfigurationValue($key, $value);
+ }
+
+ protected function parseLinterOutput($path, $err, $stdout, $stderr) {
+ $results = phutil_json_decode($stdout);
+ $messages = array();
+
+ foreach ($results['files'] as $file) {
+ foreach ($file['offenses'] as $offense) {
+ $message = new ArcanistLintMessage();
+
+ $message->setPath($file['path']);
+ $message->setDescription($offense['message']);
+
+ $message->setLine($offense['location']['line']);
+ $message->setChar($offense['location']['column']);
+
+ switch ($offense['severity']) {
+ case 'warning':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
+ break;
+ case 'error':
+ case 'fatal':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
+ break;
+ default:
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
+ break;
+ }
+
+ $message->setName($this->getLinterName());
+ $message->setCode($offense['cop_name']);
+
+ $messages[] = $message;
+ }
+ }
+
+ return $messages;
+ }
+}
diff --git a/src/lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php b/src/lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php
@@ -0,0 +1,12 @@
+<?php
+
+final class ArcanistRuboCopLinterTestCase
+ extends ArcanistArcanistLinterTestCase {
+
+ public function testRuboCopLinter() {
+ $this->executeTestsInDirectory(
+ dirname(__FILE__).'/rubocop/',
+ new ArcanistRuboCopLinter());
+ }
+
+}
diff --git a/src/lint/linter/__tests__/rubocop/convention.lint-test b/src/lint/linter/__tests__/rubocop/convention.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/rubocop/convention.lint-test
@@ -0,0 +1,4 @@
+def hello()
+end
+~~~~~~~~~~
+advice:1:10
diff --git a/src/lint/linter/__tests__/rubocop/error.lint-test b/src/lint/linter/__tests__/rubocop/error.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/rubocop/error.lint-test
@@ -0,0 +1,4 @@
+def hello
+ puts 'world'
+~~~~~~~~~~
+error:3:1
diff --git a/src/lint/linter/__tests__/rubocop/no_errors.lint-test b/src/lint/linter/__tests__/rubocop/no_errors.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/rubocop/no_errors.lint-test
@@ -0,0 +1,4 @@
+def hello
+ puts 'hello world'
+end
+~~~~~~~~~~
diff --git a/src/lint/linter/__tests__/rubocop/warning.lint-test b/src/lint/linter/__tests__/rubocop/warning.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/rubocop/warning.lint-test
@@ -0,0 +1,5 @@
+def hello(unused)
+ puts 'hi'
+end
+~~~~~~~~~
+warning:1:11

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 5, 10:11 PM (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7227609
Default Alt Text
D10738.id26566.diff (6 KB)

Event Timeline