1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-25 16:22:42 +01:00

Add ArcanistLintSeverity::SEVERITY_AUTOFIX.

Summary:
Xcode (a popular code editor on Mac OS X) has no facility
to trim trailing whitespace automatically.

This adds a new lint severity "AUTOFIX" that's between
WARNING and ERROR. When running the linter, any lint message
whose severity is AUTOFIX will automatically be patched.

Furthermore, if all lint messages returned from the engine are
AUTOFIX, we'll automatically amend HEAD with the patch.

Test Plan:
arc lint on files with and without trailing whitespace,
with and without UTF-8 contents to confirm those still error

Reviewers: epriestley, jungejason

Reviewed By: epriestley

CC: aran

Differential Revision: https://secure.phabricator.com/D2125
This commit is contained in:
Ben Gertzfield 2012-04-06 12:23:19 -07:00
parent 55dce2beeb
commit 14d49d2565
7 changed files with 114 additions and 10 deletions

View file

@ -49,6 +49,7 @@ final class ArcanistTextLinter extends ArcanistLinter {
public function getLintSeverityMap() { public function getLintSeverityMap() {
return array( return array(
self::LINT_LINE_WRAP => ArcanistLintSeverity::SEVERITY_WARNING, self::LINT_LINE_WRAP => ArcanistLintSeverity::SEVERITY_WARNING,
self::LINT_TRAILING_WHITESPACE => ArcanistLintSeverity::SEVERITY_AUTOFIX,
); );
} }

View file

@ -144,6 +144,10 @@ final class ArcanistLintMessage {
return $this->getSeverity() == ArcanistLintSeverity::SEVERITY_WARNING; return $this->getSeverity() == ArcanistLintSeverity::SEVERITY_WARNING;
} }
public function isAutofix() {
return $this->getSeverity() == ArcanistLintSeverity::SEVERITY_AUTOFIX;
}
public function hasFileContext() { public function hasFileContext() {
return ($this->getLine() !== null); return ($this->getLine() !== null);
} }

View file

@ -22,6 +22,13 @@
* @group lint * @group lint
*/ */
final class ArcanistLintRenderer { final class ArcanistLintRenderer {
private $showAutofixPatches = false;
public function setShowAutofixPatches($show_autofix_patches) {
$this->showAutofixPatches = $show_autofix_patches;
return $this;
}
public function renderLintResult(ArcanistLintResult $result) { public function renderLintResult(ArcanistLintResult $result) {
$messages = $result->getMessages(); $messages = $result->getMessages();
$path = $result->getPath(); $path = $result->getPath();
@ -29,9 +36,12 @@ final class ArcanistLintRenderer {
$lines = explode("\n", $result->getData()); $lines = explode("\n", $result->getData());
$text = array(); $text = array();
$text[] = phutil_console_format('**>>>** Lint for __%s__:', $path);
$text[] = null;
foreach ($messages as $message) { foreach ($messages as $message) {
if (!$this->showAutofixPatches && $message->isAutofix()) {
continue;
}
if ($message->isError()) { if ($message->isError()) {
$color = 'red'; $color = 'red';
} else { } else {
@ -55,10 +65,13 @@ final class ArcanistLintRenderer {
$text[] = $this->renderContext($message, $lines); $text[] = $this->renderContext($message, $lines);
} }
} }
$text[] = null;
$text[] = null;
return implode("\n", $text); if ($text) {
$prefix = phutil_console_format("**>>>** Lint for __%s__:\n\n\n", $path);
return $prefix . implode("\n", $text);
} else {
return null;
}
} }
protected function renderContext( protected function renderContext(

View file

@ -79,6 +79,15 @@ final class ArcanistLintResult {
return false; return false;
} }
public function isAllAutofix() {
foreach ($this->messages as $message) {
if (!$message->isAutofix()) {
return false;
}
}
return true;
}
private function sortAndFilterMessages() { private function sortAndFilterMessages() {
$messages = $this->messages; $messages = $this->messages;

View file

@ -24,6 +24,7 @@
final class ArcanistLintSeverity { final class ArcanistLintSeverity {
const SEVERITY_ADVICE = 'advice'; const SEVERITY_ADVICE = 'advice';
const SEVERITY_AUTOFIX = 'autofix';
const SEVERITY_WARNING = 'warning'; const SEVERITY_WARNING = 'warning';
const SEVERITY_ERROR = 'error'; const SEVERITY_ERROR = 'error';
const SEVERITY_DISABLED = 'disabled'; const SEVERITY_DISABLED = 'disabled';
@ -31,6 +32,7 @@ final class ArcanistLintSeverity {
public static function getStringForSeverity($severity_code) { public static function getStringForSeverity($severity_code) {
static $map = array( static $map = array(
self::SEVERITY_ADVICE => 'Advice', self::SEVERITY_ADVICE => 'Advice',
self::SEVERITY_AUTOFIX => 'Auto-Fix',
self::SEVERITY_WARNING => 'Warning', self::SEVERITY_WARNING => 'Warning',
self::SEVERITY_ERROR => 'Error', self::SEVERITY_ERROR => 'Error',
self::SEVERITY_DISABLED => 'Disabled', self::SEVERITY_DISABLED => 'Disabled',
@ -50,6 +52,7 @@ final class ArcanistLintSeverity {
static $map = array( static $map = array(
self::SEVERITY_DISABLED => 10, self::SEVERITY_DISABLED => 10,
self::SEVERITY_ADVICE => 20, self::SEVERITY_ADVICE => 20,
self::SEVERITY_AUTOFIX => 25,
self::SEVERITY_WARNING => 30, self::SEVERITY_WARNING => 30,
self::SEVERITY_ERROR => 40, self::SEVERITY_ERROR => 40,
); );

View file

@ -276,6 +276,22 @@ EOTEXT
'lint' => true, 'lint' => true,
), ),
), ),
'amend-all' => array(
'help' =>
'When linting git repositories, amend HEAD with all patches '.
'suggested by lint without prompting.',
'passthru' => array(
'lint' => true,
),
),
'amend-autofixes' => array(
'help' =>
'When linting git repositories, amend HEAD with autofix '.
'patches suggested by lint without prompting.',
'passthru' => array(
'lint' => true,
),
),
'json' => array( 'json' => array(
'help' => 'help' =>
'Emit machine-readable JSON. EXPERIMENTAL! Probably does not work!', 'Emit machine-readable JSON. EXPERIMENTAL! Probably does not work!',

View file

@ -30,12 +30,24 @@ class ArcanistLintWorkflow extends ArcanistBaseWorkflow {
private $unresolvedMessages; private $unresolvedMessages;
private $shouldAmendChanges = false; private $shouldAmendChanges = false;
private $shouldAmendWithoutPrompt = false;
private $shouldAmendAutofixesWithoutPrompt = false;
public function setShouldAmendChanges($should_amend) { public function setShouldAmendChanges($should_amend) {
$this->shouldAmendChanges = $should_amend; $this->shouldAmendChanges = $should_amend;
return $this; return $this;
} }
public function setShouldAmendWithoutPrompt($should_amend) {
$this->shouldAmendWithoutPrompt = $should_amend;
return $this;
}
public function setShouldAmendAutofixesWithoutPrompt($should_amend) {
$this->shouldAmendAutofixesWithoutPrompt = $should_amend;
return $this;
}
public function getCommandSynopses() { public function getCommandSynopses() {
return phutil_console_format(<<<EOTEXT return phutil_console_format(<<<EOTEXT
**lint** [__options__] [__paths__] **lint** [__options__] [__paths__]
@ -100,6 +112,16 @@ EOTEXT
'apply-patches' => true, 'apply-patches' => true,
), ),
), ),
'amend-all' => array(
'help' =>
'When linting git repositories, amend HEAD with all patches '.
'suggested by lint without prompting.',
),
'amend-autofixes' => array(
'help' =>
'When linting git repositories, amend HEAD with autofix '.
'patches suggested by lint without prompting.',
),
'*' => 'paths', '*' => 'paths',
); );
} }
@ -155,7 +177,7 @@ EOTEXT
if ($this->getArgument('advice')) { if ($this->getArgument('advice')) {
$engine->setMinimumSeverity(ArcanistLintSeverity::SEVERITY_ADVICE); $engine->setMinimumSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
} else { } else {
$engine->setMinimumSeverity(ArcanistLintSeverity::SEVERITY_WARNING); $engine->setMinimumSeverity(ArcanistLintSeverity::SEVERITY_AUTOFIX);
} }
// Propagate information about which lines changed to the lint engine. // Propagate information about which lines changed to the lint engine.
@ -186,6 +208,19 @@ EOTEXT
$prompt_patches = true; $prompt_patches = true;
} }
if ($this->getArgument('amend-all')) {
$this->shouldAmendChanges = true;
$this->shouldAmendWithoutPrompt = true;
}
if ($this->getArgument('amend-autofixes')) {
$prompt_autofix_patches = false;
$this->shouldAmendChanges = true;
$this->shouldAmendAutofixesWithoutPrompt = true;
} else {
$prompt_autofix_patches = true;
}
$wrote_to_disk = false; $wrote_to_disk = false;
switch ($this->getArgument('output')) { switch ($this->getArgument('output')) {
@ -204,22 +239,35 @@ EOTEXT
break; break;
default: default:
$renderer = new ArcanistLintRenderer(); $renderer = new ArcanistLintRenderer();
$renderer->setShowAutofixPatches($prompt_autofix_patches);
break; break;
} }
$all_autofix = true;
foreach ($results as $result) { foreach ($results as $result) {
if (!$result->getMessages()) { $result_all_autofix = $result->isAllAutofix();
if (!$result->getMessages() && !$result_all_autofix) {
continue; continue;
} }
echo $renderer->renderLintResult($result); if (!$result_all_autofix) {
$all_autofix = false;
}
$lint_result = $renderer->renderLintResult($result);
if ($lint_result) {
echo $lint_result;
}
if ($apply_patches && $result->isPatchable()) { if ($apply_patches && $result->isPatchable()) {
$patcher = ArcanistLintPatcher::newFromArcanistLintResult($result); $patcher = ArcanistLintPatcher::newFromArcanistLintResult($result);
$old = $patcher->getUnmodifiedFileContent(); $old = $patcher->getUnmodifiedFileContent();
$new = $patcher->getModifiedFileContent(); $new = $patcher->getModifiedFileContent();
if ($prompt_patches) { if ($prompt_patches &&
!($result_all_autofix && !$prompt_autofix_patches)) {
$old_file = $result->getFilePathOnDisk(); $old_file = $result->getFilePathOnDisk();
if (!Filesystem::pathExists($old_file)) { if (!Filesystem::pathExists($old_file)) {
$old_file = '/dev/null'; $old_file = '/dev/null';
@ -248,7 +296,17 @@ EOTEXT
if ($wrote_to_disk && if ($wrote_to_disk &&
($repository_api instanceof ArcanistGitAPI) && ($repository_api instanceof ArcanistGitAPI) &&
$this->shouldAmendChanges) { $this->shouldAmendChanges) {
$amend = phutil_console_confirm("Amend HEAD with lint patches?");
if ($this->shouldAmendWithoutPrompt ||
($this->shouldAmendAutofixesWithoutPrompt && $all_autofix)) {
echo phutil_console_format(
"<bg:yellow>** LINT NOTICE **</bg> Automatically amending HEAD ".
"with lint patches.\n");
$amend = true;
} else {
$amend = phutil_console_confirm("Amend HEAD with lint patches?");
}
if ($amend) { if ($amend) {
execx( execx(
'(cd %s; git commit -a --amend -C HEAD)', '(cd %s; git commit -a --amend -C HEAD)',