diff --git a/.divinerconfig b/.divinerconfig index 11a99d8c..f36ed9c8 100644 --- a/.divinerconfig +++ b/.divinerconfig @@ -3,7 +3,17 @@ "src_base" : "https://github.com/facebook/arcanist/blob/master", "groups" : { "intro" : "Introduction", - "config" : "Setup & Configuration" + "config" : "Setup & Configuration", + "workflow" : "Workflows", + "lint" : "Lint Integration", + "linter" : "Linters", + "unit" : "Unit Test Integration", + "unitrun" : "Unit Test Runners", + "diff" : "Diff and Changeset APIs", + "differential" : "Differential Integration", + "workingcopy" : "Working Copy APIs", + "module" : "Phutil Module System", + "testcase" : "Test Cases" } } diff --git a/scripts/arcanist.php b/scripts/arcanist.php index b4de5327..dfd7309e 100755 --- a/scripts/arcanist.php +++ b/scripts/arcanist.php @@ -30,6 +30,8 @@ phutil_require_module('arcanist', 'configuration'); phutil_require_module('arcanist', 'workingcopyidentity'); phutil_require_module('arcanist', 'repository/api/base'); +ini_set('memory_limit', -1); + $config_trace_mode = false; $force_conduit = null; $args = array_slice($argv, 1); diff --git a/scripts/phutil_analyzer.php b/scripts/phutil_analyzer.php index 3e89ff3d..c5dc4ea1 100755 --- a/scripts/phutil_analyzer.php +++ b/scripts/phutil_analyzer.php @@ -53,7 +53,7 @@ phutil_require_module('phutil', 'parser/xhpast/api/tree'); phutil_require_module('arcanist', 'lint/linter/phutilmodule'); phutil_require_module('arcanist', 'lint/message'); -phutil_require_module('arcanist', 'staticanalysis/parsers/phutilmodule'); +phutil_require_module('arcanist', 'parser/phutilmodule'); $data = array(); @@ -114,7 +114,7 @@ foreach (Futures($futures) as $file => $future) { } $requirements->addSourceDependency($name, $value); } else if ($call_name == 'phutil_require_module') { - analyze_require_module($call, $requirements); + analyze_phutil_require_module($call, $requirements); } } } else { @@ -146,7 +146,7 @@ foreach (Futures($futures) as $file => $future) { $call_name = $name->getConcreteString(); if ($call_name == 'phutil_require_module') { - analyze_require_module($call, $requirements); + analyze_phutil_require_module($call, $requirements); } else if ($call_name == 'call_user_func' || $call_name == 'call_user_func_array') { $params = $call->getChildByIndex(1)->getChildren(); @@ -307,7 +307,12 @@ if (!$has_init && $has_files) { echo json_encode($requirements->toDictionary()); -function analyze_require_module( +/** + * Parses meaning from calls to phutil_require_module() in __init__.php files. + * + * @group module + */ +function analyze_phutil_require_module( XHPASTNode $call, PhutilModuleRequirements $requirements) { diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index d0d784a4..f9fe6907 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -68,7 +68,7 @@ phutil_register_library_map(array( 'ArcanistXHPASTLinter' => 'lint/linter/xhpast', 'ArcanistXHPASTLinterTestCase' => 'lint/linter/xhpast/__tests__', 'PhutilLintEngine' => 'lint/engine/phutil', - 'PhutilModuleRequirements' => 'staticanalysis/parsers/phutilmodule', + 'PhutilModuleRequirements' => 'parser/phutilmodule', 'PhutilUnitTestEngine' => 'unit/engine/phutil', 'PhutilUnitTestEngineTestCase' => 'unit/engine/phutil/__tests__', 'UnitTestableArcanistLintEngine' => 'lint/engine/test', diff --git a/src/configuration/ArcanistConfiguration.php b/src/configuration/ArcanistConfiguration.php index 1f5c2389..64cb22cc 100644 --- a/src/configuration/ArcanistConfiguration.php +++ b/src/configuration/ArcanistConfiguration.php @@ -16,6 +16,28 @@ * limitations under the License. */ +/** + * Runtime workflow configuration. In Arcanist, commands you type like + * "arc diff" or "arc lint" are called "workflows". This class allows you to add + * new workflows (and extend existing workflows) by subclassing it and then + * pointing to your subclass in your project configuration. + * + * For instructions on how to extend this class and customize Arcanist in your + * project, see @{article:Building New Configuration Classes}. + * + * When specified as the **arcanist_configuration** class in your project's + * ##.arcconfig##, your subclass will be instantiated (instead of this class) + * and be able to handle all the method calls. In particular, you can: + * + * - create, replace, or disable workflows by overriding buildWorkflow() + * and buildAllWorkflows(); + * - add additional steps before or after workflows run by overriding + * willRunWorkflow() or didRunWorkflow(); and + * - add new flags to existing workflows by overriding + * getCustomArgumentsForCommand(). + * + * @group config + */ class ArcanistConfiguration { public function buildWorkflow($command) { diff --git a/src/difference/ArcanistDiffUtils.php b/src/difference/ArcanistDiffUtils.php index 9ff4f040..e1534cfb 100644 --- a/src/difference/ArcanistDiffUtils.php +++ b/src/difference/ArcanistDiffUtils.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Dumping ground for diff- and diff-algorithm-related miscellany. + * + * @group diff + */ final class ArcanistDiffUtils { public static function renderDifferences( diff --git a/src/differential/commitmessage/ArcanistDifferentialCommitMessage.php b/src/differential/commitmessage/ArcanistDifferentialCommitMessage.php index 728397ca..3b0328ef 100644 --- a/src/differential/commitmessage/ArcanistDifferentialCommitMessage.php +++ b/src/differential/commitmessage/ArcanistDifferentialCommitMessage.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Represents a parsed commit message. + * + * @group differential + */ class ArcanistDifferentialCommitMessage { private $rawCorpus; diff --git a/src/differential/commitmessage/ArcanistDifferentialCommitMessageParserException.php b/src/differential/commitmessage/ArcanistDifferentialCommitMessageParserException.php index 37122995..41ea5cd2 100644 --- a/src/differential/commitmessage/ArcanistDifferentialCommitMessageParserException.php +++ b/src/differential/commitmessage/ArcanistDifferentialCommitMessageParserException.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Thrown when a commit message isn't parseable. + * + * @group differential + */ class ArcanistDifferentialCommitMessageParserException extends Exception { } diff --git a/src/differential/revision/ArcanistDifferentialRevisionRef.php b/src/differential/revision/ArcanistDifferentialRevisionRef.php index da866c24..8e6c19ff 100644 --- a/src/differential/revision/ArcanistDifferentialRevisionRef.php +++ b/src/differential/revision/ArcanistDifferentialRevisionRef.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Reference to a Differential revision. + * + * @group differential + */ class ArcanistDifferentialRevisionRef { protected $id; diff --git a/src/docs/arcconfig.diviner b/src/docs/arcconfig.diviner index c7085e4c..0ae197e2 100644 --- a/src/docs/arcconfig.diviner +++ b/src/docs/arcconfig.diviner @@ -1,8 +1,7 @@ @title Setting Up .arcconfig @group config -This document describes how to configure Arcanist projects with ##.arcconfig## -files. +Explains how to configure Arcanist projects with ##.arcconfig## files. = .arcconfig Basics = diff --git a/src/docs/building_new_configuration_classes.diviner b/src/docs/building_new_configuration_classes.diviner new file mode 100644 index 00000000..6fb31617 --- /dev/null +++ b/src/docs/building_new_configuration_classes.diviner @@ -0,0 +1,83 @@ +@title Building New Configuration Classes +@group config + +Explains how to build new classes to control how Arcanist behaves. + += Overview = + +Arcanist has some basic configuration options available in the ##.arcconfig## +file (see @{article:Setting Up .arcconfig}), but it can't handle everything. If +you want to customize Arcanist at a deeper level, you need to build new classes. +For instance: + + - if you want to configure linters, or add new linters, you need to create a + new class which extends @{class:ArcanistLintEngine}. + - if you want to integrate with a unit testing framework, you need to create a + new class which extends @{class:ArcanistBaseUnitTestEngine}. + - if you you want to change how workflows behave, or add new workflows, you + need to create a new class which extends @{class:ArcanistConfiguration}. + +Arcanist works through a sort of dependency-injection approach. For example, +Arcanist does not run lint rules by default, but you can set **lint_engine** +in your ##.arcconfig## to the name of a class which extends +@{class:ArcanistLintEngine}. When running from inside your project, Arcanist +will load this class and call methods on it in order to run lint. To make this +work, you need to do three things: + + - actually write the class; + - add the library where the class exists to your ##.arcconfig##; + - add the class name to your ##.arcconfig## as the **lint_engine**, + **unit_engine**, or **arcanist_configuration**. + += Write the Class = + +(TODO) + += Load the Class = + +To make the class loadable, you need to put the path to it in your +##.arcconfig##, under **phutil_libraries**: + + { + // ... + "phutil_libraries" : { + // ... + "my-library" : "/path/to/my/library", + // ... + } + // ... + } + +You can either specify an absolute path, or a path relative to the project root. +When you run ##arc --trace##, you should see a message to the effect that it has +loaded your library. + +For debugging or testing, you can also run Arcanist with the +##--load-phutil-library## flag: + + arc --load-phutil-library=/path/to/library + +You can specify this flag more than once to load several libraries. Note that +if you use this flag, Arcanist will ignore any libraries listed in +##.arcconfig##. + += Use the Class = + +This step is easy: just edit ##.arcconfig## to specify your class name as +the appropriate configuration value. + + { + // ... + "lint_engine" : "MyCustomArcanistLintEngine", + // ... + } + +Now, when you run Arcanist in your project, it will invoke your class when +appropriate. + +For lint and unit tests, you can also use the ##--engine## flag override the +default engine: + + arc lint --engine MyCustomArcanistLintEngine + +This is mostly useful for debugging and testing. diff --git a/src/docs/overview.diviner b/src/docs/overview.diviner index 0bc22578..f785ad97 100644 --- a/src/docs/overview.diviner +++ b/src/docs/overview.diviner @@ -1,10 +1,10 @@ @title Arcanist Overview @group intro -This document provides an overview of Arcanist, a code workflow tool. Arcanist -(commonly, "arc") is the command-line frontend to Differential. +Overview of Arcanist, a code workflow tool. -A detailed command reference is available by running ##arc help##. +Arcanist (commonly, "arc") is the command-line frontend to Differential. A +detailed command reference is available by running ##arc help##. = Overview = diff --git a/src/docs/svn_hooks.diviner b/src/docs/svn_hooks.diviner index 3605299f..27c4d908 100644 --- a/src/docs/svn_hooks.diviner +++ b/src/docs/svn_hooks.diviner @@ -1,6 +1,8 @@ @title Installing Arcanist SVN Hooks @group config +Describes how to set up Arcanist as an SVN pre-commit hook. + = Installing Arcanist SVN Hooks = You can install Arcanist as an SVN pre-commit hook, to reject commits which diff --git a/src/exception/ArcanistChooseInvalidRevisionException.php b/src/exception/ArcanistChooseInvalidRevisionException.php index 85664e25..f49558d3 100644 --- a/src/exception/ArcanistChooseInvalidRevisionException.php +++ b/src/exception/ArcanistChooseInvalidRevisionException.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Thrown when the user chooses an invalid revision when prompted by a workflow. + * + * @group workflow + */ class ArcanistChooseInvalidRevisionException extends Exception { } diff --git a/src/exception/ArcanistChooseNoRevisionsException.php b/src/exception/ArcanistChooseNoRevisionsException.php index 95842572..cc8d1a73 100644 --- a/src/exception/ArcanistChooseNoRevisionsException.php +++ b/src/exception/ArcanistChooseNoRevisionsException.php @@ -16,6 +16,12 @@ * limitations under the License. */ +/** + * Thrown when there are no valid revisions to choose from, in a workflow which + * prompts the user to choose a revision. + * + * @group workflow + */ class ArcanistChooseNoRevisionsException extends Exception { } diff --git a/src/exception/usage/ArcanistUsageException.php b/src/exception/usage/ArcanistUsageException.php index b2054dbe..1948c69b 100644 --- a/src/exception/usage/ArcanistUsageException.php +++ b/src/exception/usage/ArcanistUsageException.php @@ -16,6 +16,12 @@ * limitations under the License. */ +/** + * Thrown when there is a problem with how a user is invoking a command, rather + * than a technical problem. + * + * @group workflow + */ class ArcanistUsageException extends Exception { } diff --git a/src/exception/usage/noeffect/ArcanistNoEffectException.php b/src/exception/usage/noeffect/ArcanistNoEffectException.php index 4324fb35..fed8371e 100644 --- a/src/exception/usage/noeffect/ArcanistNoEffectException.php +++ b/src/exception/usage/noeffect/ArcanistNoEffectException.php @@ -16,5 +16,11 @@ * limitations under the License. */ +/** + * Thrown when lint or unit tests have no effect, i.e. no paths are affected + * by any linter or no unit tests provide coverage. + * + * @group workflow + */ class ArcanistNoEffectException extends ArcanistUsageException { } diff --git a/src/exception/usage/noengine/ArcanistNoEngineException.php b/src/exception/usage/noengine/ArcanistNoEngineException.php index 416963ce..5a118af9 100644 --- a/src/exception/usage/noengine/ArcanistNoEngineException.php +++ b/src/exception/usage/noengine/ArcanistNoEngineException.php @@ -16,5 +16,10 @@ * limitations under the License. */ +/** + * Thrown when no engine is configured for linting or running unit tests. + * + * @group workflow + */ class ArcanistNoEngineException extends ArcanistUsageException { } diff --git a/src/exception/usage/userabort/ArcanistUserAbortException.php b/src/exception/usage/userabort/ArcanistUserAbortException.php index a22ccd08..43b6c05f 100644 --- a/src/exception/usage/userabort/ArcanistUserAbortException.php +++ b/src/exception/usage/userabort/ArcanistUserAbortException.php @@ -16,6 +16,12 @@ * limitations under the License. */ +/** + * Thrown when the user chooses not to continue when warned that they're about + * to do something dangerous. + * + * @group workflow + */ class ArcanistUserAbortException extends ArcanistUsageException { public function __construct() { parent::__construct('User aborted the workflow.'); diff --git a/src/lint/engine/base/ArcanistLintEngine.php b/src/lint/engine/base/ArcanistLintEngine.php index 2f4071b3..7d51b603 100644 --- a/src/lint/engine/base/ArcanistLintEngine.php +++ b/src/lint/engine/base/ArcanistLintEngine.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Manages lint execution. + * + * @group lint + */ abstract class ArcanistLintEngine { protected $workingCopy; diff --git a/src/lint/engine/phutil/PhutilLintEngine.php b/src/lint/engine/phutil/PhutilLintEngine.php index d393c8c9..d923c166 100644 --- a/src/lint/engine/phutil/PhutilLintEngine.php +++ b/src/lint/engine/phutil/PhutilLintEngine.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Lint engine which enforces libphutil rules. + * + * @group linter + */ class PhutilLintEngine extends ArcanistLintEngine { public function buildLinters() { diff --git a/src/lint/engine/test/UnitTestableArcanistLintEngine.php b/src/lint/engine/test/UnitTestableArcanistLintEngine.php index 84246d8b..cbb71bec 100644 --- a/src/lint/engine/test/UnitTestableArcanistLintEngine.php +++ b/src/lint/engine/test/UnitTestableArcanistLintEngine.php @@ -16,6 +16,12 @@ * limitations under the License. */ +/** + * Lint engine for use in constructing test cases. See + * @{class:ArcanistLinterTestCase}. + * + * @group testcase + */ final class UnitTestableArcanistLintEngine extends ArcanistLintEngine { protected $linters = array(); diff --git a/src/lint/linter/apachelicense/ArcanistApacheLicenseLinter.php b/src/lint/linter/apachelicense/ArcanistApacheLicenseLinter.php index 3029b3b4..f150572a 100644 --- a/src/lint/linter/apachelicense/ArcanistApacheLicenseLinter.php +++ b/src/lint/linter/apachelicense/ArcanistApacheLicenseLinter.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Adds the Apache license to source files. + * + * @group linter + */ class ArcanistApacheLicenseLinter extends ArcanistLicenseLinter { public function getLinterName() { return 'APACHELICENSE'; diff --git a/src/lint/linter/apachelicense/__tests__/ArcanistApacheLicenseLinterTestCase.php b/src/lint/linter/apachelicense/__tests__/ArcanistApacheLicenseLinterTestCase.php index 96643aea..9015e2e2 100644 --- a/src/lint/linter/apachelicense/__tests__/ArcanistApacheLicenseLinterTestCase.php +++ b/src/lint/linter/apachelicense/__tests__/ArcanistApacheLicenseLinterTestCase.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Test cases for @{class:ArcanistApacheLicenseLinter}. + * + * @group testcase + */ class ArcanistApacheLicenseLinterTestCase extends ArcanistLinterTestCase { public function testApacheLicenseLint() { diff --git a/src/lint/linter/base/ArcanistLinter.php b/src/lint/linter/base/ArcanistLinter.php index 4474418b..b704c41d 100644 --- a/src/lint/linter/base/ArcanistLinter.php +++ b/src/lint/linter/base/ArcanistLinter.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Implements lint rules, like syntax checks for a specific language. + * + * @group linter + */ abstract class ArcanistLinter { protected $paths = array(); diff --git a/src/lint/linter/base/test/ArcanistLinterTestCase.php b/src/lint/linter/base/test/ArcanistLinterTestCase.php index 8b02bdf1..0a4bff4a 100644 --- a/src/lint/linter/base/test/ArcanistLinterTestCase.php +++ b/src/lint/linter/base/test/ArcanistLinterTestCase.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Facilitiates implementation of test cases for @{class:ArcanistLinter}s. + * + * @group testcase + */ abstract class ArcanistLinterTestCase extends ArcanistPhutilTestCase { public function executeTestsInDirectory($root, $linter, $working_copy) { diff --git a/src/lint/linter/filename/ArcanistFilenameLinter.php b/src/lint/linter/filename/ArcanistFilenameLinter.php index bd5659c6..f5630c03 100644 --- a/src/lint/linter/filename/ArcanistFilenameLinter.php +++ b/src/lint/linter/filename/ArcanistFilenameLinter.php @@ -16,6 +16,11 @@ * limitations under the License. */ +/** + * Stifles creativity in choosing imaginative file names. + * + * @group linter + */ class ArcanistFilenameLinter extends ArcanistLinter { const LINT_BAD_FILENAME = 1; diff --git a/src/lint/linter/generated/ArcanistGeneratedLinter.php b/src/lint/linter/generated/ArcanistGeneratedLinter.php index 15116302..db739091 100644 --- a/src/lint/linter/generated/ArcanistGeneratedLinter.php +++ b/src/lint/linter/generated/ArcanistGeneratedLinter.php @@ -1,8 +1,9 @@