mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 08:12:40 +01:00
Added RuboCop linter
Test Plan: Add the following JSON to your `.arclint`: ```lang=json "rubocop": { "type": "rubocop", "include": "(\\.rb$)" } ``` Then, add a ruby file with errors, for instance: ```lang=ruby def hello() puts 'world' end ``` Run `arc lint`. It should come up with something along the line of: "Omit the parentheses in defs when the method doesn't accept any arguments." Reviewers: joshuaspence, remon, #blessed_reviewers, epriestley Reviewed By: joshuaspence, #blessed_reviewers, epriestley Subscribers: reu, calfzhou, jjooss, cburroughs, chad, Korvin, epriestley Differential Revision: https://secure.phabricator.com/D10738
This commit is contained in:
parent
3eacb08273
commit
41ddd34aeb
7 changed files with 151 additions and 0 deletions
|
@ -161,6 +161,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistRepositoryAPIMiscTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIMiscTestCase.php',
|
'ArcanistRepositoryAPIMiscTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIMiscTestCase.php',
|
||||||
'ArcanistRepositoryAPIStateTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php',
|
'ArcanistRepositoryAPIStateTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php',
|
||||||
'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php',
|
'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php',
|
||||||
|
'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
|
||||||
|
'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
|
||||||
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
|
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
|
||||||
'ArcanistRubyLinterTestCase' => 'lint/linter/__tests__/ArcanistRubyLinterTestCase.php',
|
'ArcanistRubyLinterTestCase' => 'lint/linter/__tests__/ArcanistRubyLinterTestCase.php',
|
||||||
'ArcanistScriptAndRegexLinter' => 'lint/linter/ArcanistScriptAndRegexLinter.php',
|
'ArcanistScriptAndRegexLinter' => 'lint/linter/ArcanistScriptAndRegexLinter.php',
|
||||||
|
@ -347,6 +349,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistRepositoryAPIMiscTestCase' => 'ArcanistTestCase',
|
'ArcanistRepositoryAPIMiscTestCase' => 'ArcanistTestCase',
|
||||||
'ArcanistRepositoryAPIStateTestCase' => 'ArcanistTestCase',
|
'ArcanistRepositoryAPIStateTestCase' => 'ArcanistTestCase',
|
||||||
'ArcanistRevertWorkflow' => 'ArcanistWorkflow',
|
'ArcanistRevertWorkflow' => 'ArcanistWorkflow',
|
||||||
|
'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
|
||||||
|
'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||||
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
|
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
|
||||||
'ArcanistRubyLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
'ArcanistRubyLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||||
'ArcanistScriptAndRegexLinter' => 'ArcanistLinter',
|
'ArcanistScriptAndRegexLinter' => 'ArcanistLinter',
|
||||||
|
|
120
src/lint/linter/ArcanistRuboCopLinter.php
Normal file
120
src/lint/linter/ArcanistRuboCopLinter.php
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
<?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 `%s`.', 'gem install rubocop');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMandatoryFlags() {
|
||||||
|
$options = array(
|
||||||
|
'--format=json',
|
||||||
|
);
|
||||||
|
|
||||||
|
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 = id(new ArcanistLintMessage())
|
||||||
|
->setPath($file['path'])
|
||||||
|
->setDescription($offense['message'])
|
||||||
|
->setLine($offense['location']['line'])
|
||||||
|
->setChar($offense['location']['column'])
|
||||||
|
->setSeverity($this->getLintMessageSeverity($offense['severity']))
|
||||||
|
->setName($this->getLinterName())
|
||||||
|
->setCode($offense['cop_name']);
|
||||||
|
$messages[] = $message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Take the string from RuboCop's severity terminology and return an
|
||||||
|
ArcanistLintSeverity
|
||||||
|
*/
|
||||||
|
protected function getDefaultMessageSeverity($code) {
|
||||||
|
switch ($code) {
|
||||||
|
case 'convention':
|
||||||
|
case 'refactor':
|
||||||
|
case 'warning':
|
||||||
|
return ArcanistLintSeverity::SEVERITY_WARNING;
|
||||||
|
case 'error':
|
||||||
|
case 'fatal':
|
||||||
|
return ArcanistLintSeverity::SEVERITY_ERROR;
|
||||||
|
default:
|
||||||
|
return ArcanistLintSeverity::SEVERITY_ADVICE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php
Normal file
10
src/lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistRuboCopLinterTestCase
|
||||||
|
extends ArcanistExternalLinterTestCase {
|
||||||
|
|
||||||
|
public function testLinter() {
|
||||||
|
$this->executeTestsInDirectory(dirname(__FILE__).'/rubocop/');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
4
src/lint/linter/__tests__/rubocop/convention.lint-test
Normal file
4
src/lint/linter/__tests__/rubocop/convention.lint-test
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
def hello()
|
||||||
|
end
|
||||||
|
~~~~~~~~~~
|
||||||
|
warning:1:10
|
4
src/lint/linter/__tests__/rubocop/error.lint-test
Normal file
4
src/lint/linter/__tests__/rubocop/error.lint-test
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
def hello
|
||||||
|
puts 'world'
|
||||||
|
~~~~~~~~~~
|
||||||
|
error:3:1
|
4
src/lint/linter/__tests__/rubocop/no_errors.lint-test
Normal file
4
src/lint/linter/__tests__/rubocop/no_errors.lint-test
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
def hello
|
||||||
|
puts 'hello world'
|
||||||
|
end
|
||||||
|
~~~~~~~~~~
|
5
src/lint/linter/__tests__/rubocop/warning.lint-test
Normal file
5
src/lint/linter/__tests__/rubocop/warning.lint-test
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
def hello(unused)
|
||||||
|
puts 'hi'
|
||||||
|
end
|
||||||
|
~~~~~~~~~
|
||||||
|
warning:1:11
|
Loading…
Reference in a new issue