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 @@ -122,6 +122,8 @@ 'ArcanistPhutilTestTerminatedException' => 'unit/engine/phutil/testcase/ArcanistPhutilTestTerminatedException.php', 'ArcanistPhutilXHPASTLinter' => 'lint/linter/ArcanistPhutilXHPASTLinter.php', 'ArcanistPhutilXHPASTLinterTestCase' => 'lint/linter/__tests__/ArcanistPhutilXHPASTLinterTestCase.php', + 'ArcanistPuppetLintLinter' => 'lint/linter/ArcanistPuppetLintLinter.php', + 'ArcanistPuppetLintLinterTestCase' => 'lint/linter/__tests__/ArcanistPuppetLintLinterTestCase.php', 'ArcanistPyFlakesLinter' => 'lint/linter/ArcanistPyFlakesLinter.php', 'ArcanistPyLintLinter' => 'lint/linter/ArcanistPyLintLinter.php', 'ArcanistRepositoryAPI' => 'repository/api/ArcanistRepositoryAPI.php', @@ -272,6 +274,8 @@ 'ArcanistPhutilTestTerminatedException' => 'Exception', 'ArcanistPhutilXHPASTLinter' => 'ArcanistBaseXHPASTLinter', 'ArcanistPhutilXHPASTLinterTestCase' => 'ArcanistArcanistLinterTestCase', + 'ArcanistPuppetLintLinter' => 'ArcanistExternalLinter', + 'ArcanistPuppetLintLinterTestCase' => 'ArcanistArcanistLinterTestCase', 'ArcanistPyFlakesLinter' => 'ArcanistLinter', 'ArcanistPyLintLinter' => 'ArcanistLinter', 'ArcanistRepositoryAPIMiscTestCase' => 'ArcanistTestCase', diff --git a/src/lint/linter/ArcanistPuppetLintLinter.php b/src/lint/linter/ArcanistPuppetLintLinter.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/ArcanistPuppetLintLinter.php @@ -0,0 +1,111 @@ +getEngine()->getConfigurationManager(); + $prefix = $config->getConfigFromAnySource('lint.puppetlint.prefix'); + $bin = $config->getConfigFromAnySource('lint.puppetlint.bin'); + + if ($bin === null) { + $bin = 'puppet-lint'; + } + + if ($prefix !== null) { + $bin = $prefix.'/'.$bin; + + if (!Filesystem::pathExists($bin)) { + throw new ArcanistUsageException( + "Unable to find puppet-lint binary in a specified directory. Make sure". + "that 'lint.puppetlint.prefix' and 'lint.puppetlint.bin' keys are set". + "correctly."); + } + } + + if (!Filesystem::binaryExists($bin)) { + throw new ArcanistUsageException( + "Puppet-lint does not appear to be installed on this system. Install". + "it (e.g., with 'gem install puppet-lint') or configure". + "'lint.puppetlint.prefix' in your .arcconfig to point to the directory". + "where it resides."); + } + + return $bin; + } + + protected function getDefaultMessageSeverity($code) { + switch ($code) { + case 'warning': + return ArcanistLintSeverity::SEVERITY_WARNING; + break; + case 'fixed': + return ArcanistLintSeverity::SEVERITY_AUTOFIX; + break; + case 'error': + // Default to error + default: + return ArcanistLintSeverity::SEVERITY_ERROR; + break; + } + } + + protected function parseLinterOutput($path, $err, $stdout, $stderr) { + if (!$stdout) { + return array(); + } + + $lines = phutil_split_lines($stdout, $retain_endings = false); + + $messages = array(); + foreach ($lines as $line) { + list($line, $column, $code, $desc) = explode(':', $line); + $message = new ArcanistLintMessage(); + $message->setPath($path); + $message->setLine($line); + $message->setChar($column); + $message->setCode($code); + $message->setDescription($desc); + $message->setSeverity($this->getLintMessageSeverity($code)); + + $messages[] = $message; + } + + if ($err && !$messages) { + return false; + } + + return $messages; + + } + +} diff --git a/src/lint/linter/__tests__/ArcanistPuppetLintLinterTestCase.php b/src/lint/linter/__tests__/ArcanistPuppetLintLinterTestCase.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/__tests__/ArcanistPuppetLintLinterTestCase.php @@ -0,0 +1,12 @@ +executeTestsInDirectory( + dirname(__FILE__).'/puppet-lint/', + new ArcanistPuppetLintLinter()); + } + +} diff --git a/src/lint/linter/__tests__/puppet-lint/basics.lint-test b/src/lint/linter/__tests__/puppet-lint/basics.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/__tests__/puppet-lint/basics.lint-test @@ -0,0 +1,9 @@ +class test { + $a = 'abc'; + b +} + +~~~~~~~~~~ +warning:1:1 +error:1:7 +error:3:4