Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15400236
D9061.id21512.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
19 KB
Referenced Files
None
Subscribers
None
D9061.id21512.diff
View Options
diff --git a/src/docs/user/userguide/arcanist_lint.diviner b/src/docs/user/userguide/arcanist_lint.diviner
--- a/src/docs/user/userguide/arcanist_lint.diviner
+++ b/src/docs/user/userguide/arcanist_lint.diviner
@@ -11,7 +11,9 @@
you haven't set up a project yet, do that first. For instructions, see
@{article:Arcanist User Guide: Configuring a New Project}.
-= Overview =
+
+Overview
+========
"Lint" refers to a general class of programming tools which analyze source code
and raise warnings and errors about it. For example, a linter might raise
@@ -35,87 +37,300 @@
languages. Arcanist ships with bindings for many popular tools, and you can
write new bindings fairly easily if you have custom tools.
-= Available Linters =
-
-Arcanist ships with bindings for these linters:
-
- - [[http://www.jshint.com/ | JSHint]], a Javascript linter.
- See @{class@arcanist:ArcanistJSHintLinter}.
- - [[http://pypi.python.org/pypi/pep8 | PEP8]],
- [[http://pypi.python.org/pypi/pyflakes | Pyflakes]],
- [[https://flake8.readthedocs.org/ | Flake8]], and
- [[http://pypi.python.org/pypi/pylint | Pylint]] - various Python linters.
- See @{class@arcanist:ArcanistPEP8Linter},
- @{class@arcanist:ArcanistPyFlakesLinter},
- @{class@arcanist:ArcanistFlake8Linter},
- and @{class@arcanist:ArcanistPyLintLinter}.
- - [[http://pear.php.net/package/PHP_CodeSniffer | PHP CodeSniffer]], a
- PHP linter. See @{class@arcanist:ArcanistPhpcsLinter}.
- - [[http://cppcheck.sourceforge.net/ | Cppcheck]] and
- [[http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py |
- cpplint.py]], two checkers for C++. See
- @{class@arcanist:ArcanistCppcheckLinter} and
- @{class@arcanist:ArcanistCpplintLinter} respectively.
- - [[https://github.com/hach-que/cstools | cslint]], a C# linting tool based on
- [[http://stylecop.codeplex.com/ | StyleCop]]. See
- @{class@arcanist:ArcanistCSharpLinter}.
- - [[http://puppet-lint.com/ | puppet-lint]], a linter for
- [[http://puppetlabs.com/ | Puppet]] manifests. See
- @{class@arcanist:ArcanistPuppetLintLinter}.
- - [[http://www.ruby-lang.org | Ruby]]'s built-in checker. See
- @{class@arcanist:ArcanistRubyLinter}.
- - [[http://www.scala-sbt.org/ | sbt]], a built tool for Scala. See
- @{class@arcanist:ArcanistScalaSBTLinter}.
- - [[http://csslint.net/ | CSSLint]], for CSS:
- @{class@arcanist:ArcanistCSSLintLinter}.
- - [[https://github.com/less/less.js | lessc]], error detection in
- [[http://lesscss.org/ | LESS]] code. @{class@arcanist:ArcanistLesscLinter}.
- - [[http://php.net/simplexml | SimpleXML]] for XML files.
- @{class@arcanist:ArcanistXMLLinter}.
-
-
-Arcanist also ships with generic bindings which can be configured to parse the
-output of a broad range of lint programs:
-
- - @{class@arcanist:ArcanistScriptAndRegexLinter}, which runs a script and
- parses its output with a regular expression.
- - @{class@arcanist:ArcanistConduitLinter}, which invokes a linter over
- Conduit and can allow you to build client/server linters.
-
-Additionally, Arcanist ships with some general purpose linters:
-
- - @{class@arcanist:ArcanistTextLinter}, which enforces basic things like
- trailing whitespace, DOS newlines, file encoding, line widths, terminal
- newlines, and tab literals.
- - @{class@arcanist:ArcanistSpellingLinter}, which can detect common spelling
- mistakes.
- - @{class@arcanist:ArcanistFilenameLinter}, which can enforce generally
- sensible rules about not giving files nonsense names.
- - @{class@arcanist:ArcanistLicenseLinter}, which can make sure license
- headers are applied to all source files.
- - @{class@arcanist:ArcanistNoLintLinter}, which can disable lint for files
- marked unlintable.
- - @{class@arcanist:ArcanistGeneratedLinter}, which can disable lint for
- generated files.
- - @{class@arcanist:ArcanistMergeConflictLinter}, which detects unresolved
- merge conflicts.
-
-Finally, Arcanist has special-purpose linters:
-
- - @{class@arcanist:ArcanistXHPASTLinter}, the PHP linter used by Phabricator
- itself. This linter is powerful, but somewhat rigid (it enforces phutil
- rules and isn't very configurable for other rulesets).
- - @{class@arcanist:ArcanistPhutilLibraryLinter}, which enforces phutil library
- layout rules.
-
-You can add support for new linters in three ways:
-
- - write new bindings and contribute them to the upstream;
- - write new bindings and install them alongside Arcanist; or
- - use a generic binding like @{class@arcanist:ArcanistScriptAndRegexLinter}
- and drive the integration through configuration.
-
-= Using Lint to Improve Code Review =
+
+Available Linters
+=================
+
+To see a list of available linters, run:
+
+ $ arc linters
+
+Arcanist ships with bindings for a number of linters that can check for errors
+or problems in JS, CSS, PHP, Python, C, C++, C#, Less, Puppet, Ruby, JSON, XML,
+and several other languages.
+
+Some general purpose linters are also available. These linters can check for
+cross-language issues like sensible filenames, trailing or mixed whitespace,
+character sets, spelling mistakes, and unresolved merge conflicts.
+
+If you have a tool you'd like to use as a linter that isn't supported by
+default, you can write bindings for it. For information on writing new linter
+bindings, see @{article:Arcanist User Guide: Customizing Lint, Unit Tests and
+Workflows}.
+
+
+Configuring Lint
+================
+
+To configure lint integration for your project, create a file called `.arclint`
+at the project root. This file should be in JSON format, and look like this:
+
+```lang=js
+{
+ "linters": {
+ "sample": {
+ "type": "pep8"
+ }
+ }
+}
+```
+
+Here, the key ("sample") is a human-readable label identifying the linter. The
+`type` specifies which linter to run. Use `arc linters` to find the names of
+the available linters.
+
+**Including and Excluding Files**: By default, a linter will run on every file.
+This is appropriate for some linters (like the Filename linter), but normally
+you only want to run a linter like **pep8** on Python files. To include or
+exclude files, use `include` and `exclude`:
+
+```lang=js
+{
+ "linters": {
+ "sample": {
+ "type": "pep8",
+ "include": "(\\.py$)",
+ "exclude": "(^third-party/)"
+ }
+ }
+}
+```
+
+The `include` key is a regular expression (or list of regular expressions)
+identifying paths the linter should be run on, while `exclude` is a regular
+expression (or list of regular expressions) identifying paths which it should
+not run on.
+
+Thus, this configures a **pep8** linter named "sample" which will run on files
+ending in ".py", unless they are inside the "third-party/" directory.
+
+You can also exclude files globally, so no linters run on them at all. Do this
+by specifying `exclude` at top level:
+
+```lang=js
+{
+ "exclude": "(^tests/data/)",
+ "linters": {
+ "sample": {
+ "type": "pep8",
+ "include": "(\\.py$)",
+ "exclude": "(^third-party/)"
+ }
+ }
+}
+```
+
+Here, the addition of a global `exclude` rule means no linter will be run on
+files in "tests/data/".
+
+**Running Multiple Linters**: Often, you will want to run several different
+linters. Perhaps your project has a mixture of Python and Javascript code, or
+you have some PHP and some JSON files. To run multiple linters, just list
+them in the `linters` map:
+
+```lang=js
+{
+ "linters": {
+ "jshint": {
+ "type": "jshint",
+ "include": "(\\.js$)"
+ },
+ "xml": {
+ "type": "xml",
+ "include": "(\\.xml$)"
+ }
+ }
+}
+```
+
+This will run JSHint on `.js` files, and SimpleXML on `.xml` files.
+
+**Adjusting Message Severities**: Arcanist raises lint messages at various
+severities. Each message has a different severity: for example, lint might
+find a syntax error and raise an `error` about it, and find trailing whitespace
+and raise a `warning` about it.
+
+Normally, you will be presented with lint messages as you are sending code for
+review. In that context, the severities behave like this:
+
+ - `error` When a file contains lint errors, they are always reported. These
+ are intended to be severe problems, like a syntax error. Unresoved lint
+ errors require you to confirm that you want to continue.
+ - `warning` When a file contains warnings, they are reported by default only
+ if they appear on lines that you have changed. They are intended to be
+ minor problems, like unconventional whitespace. Unresolved lint warnings
+ require you to confirm that you want to continue.
+ - `autofix` This level is like `warning`, but if the message includes patches
+ they will be applied automatically without prompting.
+ - `advice` Like warnings, these messages are only reported on changed lines.
+ They are intended to be very minor issues which may merit a note, like a
+ "TODO" comment. They do not require confirmation.
+ - `disabled` This level suppresses messages. They are not displayed. You can
+ use this to turn off a message if you don't care about the issue it
+ detects.
+
+By default, Arcanist tries to select reasonable severities for each message.
+However, you may want to make a message more or less severe, or disable it
+entirely. You can do this by providing a `severity` map:
+
+```lang=js
+{
+ "linters": {
+ "sample": {
+ "type": "pep8",
+ "severity": {
+ "E221": "disabled",
+ "E401": "warning"
+ }
+ }
+ }
+}
+```
+
+Here, the lint message "E221" (which is "multiple spaces before operator") is
+disabled, so it won't be shown. The message "E401" (which is "multiple imports
+on one line") is set to "warning" severity.
+
+If you want to remap a large number of messages, you can use `severity.rules`
+and specify regular expressions:
+
+```lang=js
+{
+ "linters": {
+ "sample": {
+ "type": "pep8",
+ "severity.rules": {
+ "(^E)": "warning",
+ "(^W)": "advice"
+ }
+ }
+ }
+}
+```
+
+This adjusts the severity of all "E" codes to "warning", and all "W" codes to
+"advice".
+
+**Locating Binaries and Interpreters**: Normally, Arcanist expects to find
+external linters (like `pep8`) in `$PATH`, and be able to run them without any
+special qualifiers. That is, it will run a command similar to:
+
+ $ pep8 example.py
+
+If you want to use a different copy of a linter binary, or invoke it in an
+explicit way, you can use `interpreter` and `bin`. These accept strings (or
+lists of strings) identifying places to look for linters. For example:
+
+
+```lang=js
+{
+ "linters": {
+ "sample": {
+ "type": "pep8",
+ "interpreter": ["python2.6", "python"],
+ "bin": ["/usr/local/bin/pep8-1.5.6", "/usr/local/bin/pep8"]
+ }
+ }
+}
+```
+
+When configured like this, `arc` will walk the `interpreter` list to find an
+available interpreter, then walk the `bin` list to find an available binary.
+If it can locate an appropriate interpreter and binary, it will execute those
+instead of the defaults. For example, this might cause it to execute a command
+similar to:
+
+ $ python2.6 /usr/local/bin/pep8-1.5.6 example.py
+
+**Additional Options**: Some linters support additional options to configure
+their behavior. You can use `arc linters` to get a list of these options and
+descriptions of what they do and how to configure them.
+
+**Running Different Rules on Different Files**: Sometimes, you may want to
+run the same linter with different rulesets on different files. To do this,
+create two copies of the linter and just give them different keys in the
+`linters` map:
+
+```lang=js
+{
+ "linters": {
+ "pep8-relaxed": {
+ "type": "pep8",
+ "include": "(^legacy/.*\\.py$)",
+ "severity.rules": {
+ "(.*)": "advice"
+ }
+ },
+ "pep8-normal": {
+ "type": "pep8",
+ "include": "(\\.py$)",
+ "exclude": "(^legacy/)"
+ }
+ }
+}
+```
+
+This example will run a relaxed version of the linter (which raises every
+message as advice) on Python files in "legacy/", and a normal version everywhere
+else.
+
+**Example .arclint Files**: You can find a collection of example files in
+`arcanist/resources/arclint/` to use as a starting point or refer to while
+configuring your own `.arclint` file.
+
+Advanced Configuration: Lint Engines
+====================================
+
+If you need to specify how linters execute in greater detail than is possible
+with `.arclint`, you can write a lint engine in PHP to extend Arcanist. This is
+an uncommon, advanced use case. The remainder of this section overviews how the
+lint internals work, and discusses how to extend Arcanist with a custom lint
+engine. If your needs are met by `.arclint`, you can skip to the next section
+of this document.
+
+The lint pipeline has two major components: linters and lint engines.
+
+**Linters** are programs which detect problems in a source file. Usually a
+linter is an external script, which Arcanist runs and passes a path to, like
+`jshint` or `pep8`.
+
+The script emits some messages, and Arcanist parses the output into structured
+errors. A piece of glue code (like @{class@arcanist:ArcanistJSHintLinter} or
+@{class@arcanist:ArcanistPEP8Linter}) handles calling the external script and
+interpreting its output.
+
+**Lint engines** coordinate linters, and decide which linters should run on
+which files. For instance, you might want to run `jshint` on all your `.js`
+files, and `pep8.py` on all your `.py` files. And you might not want to lint
+anything in `externals/` or `third-party/`, and maybe there are other files
+which you want to exclude or apply special rules for.
+
+By default, Arcanist uses the
+@{class@arcanist:ArcanistConfigurationDrivenLintEngine} engine if there is
+an `.arclint` file present in the working copy. This engine reads the `.arclint`
+file and uses it to decide which linters should be run on which paths. If no
+`.arclint` is present, Arcanist does not select an engine by default.
+
+You can write a custom lint engine instead, which can make a more powerful set
+of decisions about which linters to run on which paths. For instructions on
+writing a custom lint engine, see @{article:Arcanist User Guide: Customizing
+Lint, Unit Tests and Workflows} and @{class@arcanist:ExampleLintEngine}.
+
+To name an alternate lint engine, set `lint.engine` in your `.arcconfig` to the
+name of a class which extends @{class@arcanist:ArcanistLintEngine}. For more
+information on `.arcconfig`, see @{article:Arcanist User Guide: Configuring a
+New Project}.
+
+You can also set a default lint engine by setting `lint.engine` in your global
+user config with `arc set-config lint.engine`, or specify one explicitly with
+`arc lint --engine <engine>`. This can be useful for testing.
+
+There are several other engines bundled with Arcanist, but they are primarily
+predate `.arclint` and are effectively obsolete.
+
+
+Using Lint to Improve Code Review
+=================================
Code review is most valuable when it's about the big ideas in a change. It is
substantially less valuable when it devolves into nitpicking over style,
@@ -140,7 +355,8 @@
discussion away from stylistic nitpicks and toward useful examination of large
ideas.
-It can also provide a straightforward solution to arguments about style:
+It can also provide a straightforward solution to arguments about style, if you
+adopt a policy like this:
- If a rule is important enough that it should be enforced, the proponent must
add it to lint so it is automatically detected or fixed in the future and
@@ -151,7 +367,9 @@
This may or may not be an appropriate methodology to adopt at your organization,
but it generally puts the incentives in the right places.
-= Philosophy of Lint =
+
+Philosophy of Lint
+==================
Some general thoughts on how to develop lint effectively, based on building
lint tools at Facebook:
@@ -168,87 +386,6 @@
valuable to have the linter not only say "the convention is to put a space
after comma in a function call" but to fix it for you.
-
-= Configuring Lint =
-
-Most built in linters can be setup by creating a file named `.arclint` in the
-workspace root, which is read by
-@{class@arcanist:ArcanistConfigurationDrivenLintEngine}.
-
-It's a JSON file, which should look something like:
- {
- "linters" : {
- "sample" : {
- "type" : "pep8",
- "include" : "(\\.py$)",
- "exclude" : "(^exclude.py)",
- "severity" : {
- "E401" : "warning"
- }
- }
- }
-Where:
- - The key (`sample`) is only used for reporting,
- - `type` (`pep8`) is used to find the right linter,
- - `include` and `exclude` specify paths to run linter on, and
- - `severity` is specified by the linter implementation; Other linters may
- define other configurable values.
-
-You may specify many linters in a single `.arclint` file; For an example, see
-[[https://github.com/epriestley/arclint-examples/ | the arclint-examples
-repository]].
-
-Currently available linter types are: `csharp`, `filename`, `csslint`,
-`flake8`, `jshint`, `jsonlint`, `lessc`, `pep8`, `phpcs`, `puppet-lint`,
-`pyflakes`, `ruby`, `generated`, `nolint`, `script-and-regex`,
-`spelling`, `text`, `xml`.
-
-= Legacy Setups: Using arcconfig =
-
-Integration with linters that do not (yet) fully support `.arclint` involves two
-major components: linters and lint engines.
-
-Linters themselves are programs which detect problems in a source file. Usually
-a linter is an external script, which Arcanist runs and passes a path to, like
-`jshint` or `pep8.py`. The script emits some messages, and Arcanist parses
-the output into structured errors. A piece of glue code (like
-@{class@arcanist:ArcanistJSHintLinter} or
-@{class@arcanist:ArcanistPEP8Linter}) handles calling the external script and
-interpreting its output.
-
-Lint engines coordinate linters, and decide which linters should run on which
-files. For instance, you might want to run `jshint` on all your `.js` files,
-and `pep8.py` on all your `.py` files. And you might not want to lint anything
-in `externals/` or `third-party/`, and maybe there are other files which you
-want to exclude or apply special rules for.
-
-To configure arc for lint, you specify the name of a lint engine, and possibly
-provide some additional configuration. To name a lint engine, set `lint.engine`
-in your `.arcconfig` to the name of a class which extends
-@{class@arcanist:ArcanistLintEngine}. For more information on `.arcconfig`, see
-@{article:Arcanist User Guide: Configuring a New Project}.
-
-You can also set a default lint engine by setting `lint.engine` in your global
-user config with `arc set-config lint.engine`, or specify one explicitly with
-`arc lint --engine <engine>`.
-
-The available engines are:
-
- - @{class@arcanist:ComprehensiveLintEngine}, which runs a wide array of
- linters on many types of files. This is probably of limited use in any real
- project because it is overbroad, but is a good starting point for getting
- lint doing things.
- - @{class@arcanist:ArcanistSingleLintEngine}, which runs a single linter on
- every file unconditionally. This can be used with a glue linter like
- @{class@arcanist:ArcanistScriptAndRegexLinter} to put engine logic in an
- external script.
- - A custom engine you write. For most projects, lint rules are sufficiently
- specialized that this is the best option. For instructions on writing a
- custom lint engine, see
- @{article:Arcanist User Guide: Customizing Lint, Unit Tests and Workflows}
- and @{class@arcanist:ExampleLintEngine}.
-
-
= Next Steps =
Continue by:
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Mar 18, 10:28 AM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7698509
Default Alt Text
D9061.id21512.diff (19 KB)
Attached To
Mode
D9061: Further modernize lint documentation
Attached
Detach File
Event Timeline
Log In to Comment