diff --git a/src/toolset/ArcanistWorkflowArgument.php b/src/toolset/ArcanistWorkflowArgument.php index d56b10fb..26d71ece 100644 --- a/src/toolset/ArcanistWorkflowArgument.php +++ b/src/toolset/ArcanistWorkflowArgument.php @@ -1,109 +1,137 @@ key = $key; return $this; } public function getKey() { return $this->key; } public function setWildcard($wildcard) { $this->wildcard = $wildcard; return $this; } public function getWildcard() { return $this->wildcard; } public function setShortFlag($short_flag) { $this->shortFlag = $short_flag; return $this; } public function getShortFlag() { return $this->shortFlag; } public function setRepeatable($repeatable) { $this->repeatable = $repeatable; return $this; } public function getRepeatable() { return $this->repeatable; } + public function addRelatedConfig($related_config) { + $this->relatedConfig[] = $related_config; + return $this; + } + + public function getRelatedConfig() { + return $this->relatedConfig; + } + public function getPhutilSpecification() { $spec = array( 'name' => $this->getKey(), ); if ($this->getWildcard()) { $spec['wildcard'] = true; } $parameter = $this->getParameter(); if ($parameter !== null) { $spec['param'] = $parameter; } $help = $this->getHelp(); if ($help !== null) { + $config = $this->getRelatedConfig(); + + if ($config) { + $more = array(); + foreach ($this->getRelatedConfig() as $config) { + $more[] = tsprintf( + '%s **%s**', + pht('Related configuration:'), + $config); + } + $more = phutil_glue($more, "\n"); + $help = tsprintf("%B\n\n%B", $help, $more); + } + $spec['help'] = $help; } $short = $this->getShortFlag(); if ($short !== null) { $spec['short'] = $short; } $repeatable = $this->getRepeatable(); if ($repeatable !== null) { $spec['repeat'] = $repeatable; } return $spec; } public function setHelp($help) { + if (is_array($help)) { + $help = implode("\n\n", $help); + } + $this->help = $help; return $this; } public function getHelp() { return $this->help; } public function setParameter($parameter) { $this->parameter = $parameter; return $this; } public function getParameter() { return $this->parameter; } public function setIsPathArgument($is_path_argument) { $this->isPathArgument = $is_path_argument; return $this; } public function getIsPathArgument() { return $this->isPathArgument; } } diff --git a/src/workflow/ArcanistLandWorkflow.php b/src/workflow/ArcanistLandWorkflow.php index 104a19b4..f53cfefe 100644 --- a/src/workflow/ArcanistLandWorkflow.php +++ b/src/workflow/ArcanistLandWorkflow.php @@ -1,283 +1,332 @@ newWorkflowInformation() ->setSynopsis(pht('Publish reviewed changes.')) ->addExample(pht('**land** [__options__] [__ref__ ...]')) ->setHelp($help); } public function getWorkflowArguments() { return array( $this->newWorkflowArgument('hold') ->setHelp( pht( - 'Prepare the change to be pushed, but do not actually push it.')), + 'Prepare the changes to be pushed, but do not actually push '. + 'them.')), $this->newWorkflowArgument('keep-branches') ->setHelp( pht( 'Keep local branches around after changes are pushed. By '. - 'default, local branches are deleted after they land.')), + 'default, local branches are deleted after the changes they '. + 'contain are published.')), $this->newWorkflowArgument('onto-remote') ->setParameter('remote-name') - ->setHelp(pht('Push to a remote other than the default.')), - - // TODO: Formally allow flags to be bound to related configuration - // for documentation, e.g. "setRelatedConfiguration('arc.land.onto')". - + ->setHelp(pht('Push to a remote other than the default.')) + ->addRelatedConfig('arc.land.onto-remote'), $this->newWorkflowArgument('onto') ->setParameter('branch-name') ->setRepeatable(true) + ->addRelatedConfig('arc.land.onto') ->setHelp( - pht( - 'After merging, push changes onto a specified branch. '. - 'Specifying this flag multiple times will push multiple '. - 'branches.')), + array( + pht( + 'After merging, push changes onto a specified branch.'), + pht( + 'Specifying this flag multiple times will push to multiple '. + 'branches.'), + )), $this->newWorkflowArgument('strategy') ->setParameter('strategy-name') + ->addRelatedConfig('arc.land.strategy') ->setHelp( - pht( - // TODO: Improve this. - 'Merge using a particular strategy.')), + array( + pht( + 'Merge using a particular strategy. Supported strategies are '. + '"squash" and "merge".'), + pht( + 'The "squash" strategy collapses multiple local commits into '. + 'a single commit when publishing. It produces a linear '. + 'published history (but discards local checkpoint commits). '. + 'This is the default strategy.'), + pht( + 'The "merge" strategy generates a merge commit when publishing '. + 'that retains local checkpoint commits (but produces a '. + 'nonlinear published history). Select this strategy if you do '. + 'not want "arc land" to discard checkpoint commits.'), + )), $this->newWorkflowArgument('revision') ->setParameter('revision-identifier') ->setHelp( pht( - 'Land a specific revision, rather than determining the revisions '. - 'from the commits that are landing.')), + 'Land a specific revision, rather than determining revisions '. + 'automatically from the commits that are landing.')), $this->newWorkflowArgument('preview') ->setHelp( pht( - 'Shows the changes that will land. Does not modify the working '. + 'Show the changes that will land. Does not modify the working '. 'copy or the remote.')), $this->newWorkflowArgument('into') ->setParameter('commit-ref') ->setHelp( pht( - 'Specifies the state to merge into. By default, this is the same '. + 'Specify the state to merge into. By default, this is the same '. 'as the "onto" ref.')), $this->newWorkflowArgument('into-remote') ->setParameter('remote-name') ->setHelp( pht( 'Specifies the remote to fetch the "into" ref from. By '. 'default, this is the same as the "onto" remote.')), $this->newWorkflowArgument('into-local') ->setHelp( pht( 'Use the local "into" ref state instead of fetching it from '. 'a remote.')), $this->newWorkflowArgument('into-empty') ->setHelp( pht( 'Merge into the empty state instead of an existing state. This '. 'mode is primarily useful when creating a new repository, and '. 'selected automatically if the "onto" ref does not exist and the '. '"into" state is not specified.')), $this->newWorkflowArgument('incremental') ->setHelp( - pht( - 'When landing multiple revisions at once, push and rebase '. - 'after each operation instead of waiting until all merges '. - 'are completed. This is slower than the default behavior and '. - 'not atomic, but may make it easier to resolve conflicts and '. - 'land complicated changes by letting you make progress one '. - 'step at a time.')), + array( + pht( + 'When landing multiple revisions at once, push and rebase '. + 'after each merge completes instead of waiting until all '. + 'merges are completed to push.'), + pht( + 'This is slower than the default behavior and not atomic, '. + 'but may make it easier to resolve conflicts and land '. + 'complicated changes by allowing you to make progress one '. + 'step at a time.'), + )), $this->newWorkflowArgument('ref') ->setWildcard(true), ); } protected function newPrompts() { return array( $this->newPrompt('arc.land.large-working-set') ->setDescription( pht( 'Confirms landing more than %s commit(s) in a single operation.', new PhutilNumber($this->getLargeWorkingSetLimit()))), $this->newPrompt('arc.land.confirm') ->setDescription( pht( 'Confirms that the correct changes have been selected.')), $this->newPrompt('arc.land.implicit') ->setDescription( pht( 'Confirms that local commits which are not associated with '. 'a revision should land.')), $this->newPrompt('arc.land.unauthored') ->setDescription( pht( 'Confirms that revisions you did not author should land.')), $this->newPrompt('arc.land.changes-planned') ->setDescription( pht( 'Confirms that revisions with changes planned should land.')), $this->newPrompt('arc.land.closed') ->setDescription( pht( 'Confirms that revisions that are already closed should land.')), $this->newPrompt('arc.land.not-accepted') ->setDescription( pht( 'Confirms that revisions that are not accepted should land.')), $this->newPrompt('arc.land.open-parents') ->setDescription( pht( 'Confirms that revisions with open parent revisions should '. 'land.')), $this->newPrompt('arc.land.failed-builds') ->setDescription( pht( 'Confirms that revisions with failed builds.')), $this->newPrompt('arc.land.ongoing-builds') ->setDescription( pht( 'Confirms that revisions with ongoing builds.')), ); } public function getLargeWorkingSetLimit() { return 50; } public function runWorkflow() { $working_copy = $this->getWorkingCopy(); $repository_api = $working_copy->getRepositoryAPI(); $land_engine = $repository_api->getLandEngine(); if (!$land_engine) { throw new PhutilArgumentUsageException( pht( '"arc land" must be run in a Git or Mercurial working copy.')); } $is_incremental = $this->getArgument('incremental'); $source_refs = $this->getArgument('ref'); $onto_remote_arg = $this->getArgument('onto-remote'); $onto_args = $this->getArgument('onto'); $into_remote = $this->getArgument('into-remote'); $into_empty = $this->getArgument('into-empty'); $into_local = $this->getArgument('into-local'); $into = $this->getArgument('into'); $is_preview = $this->getArgument('preview'); $should_hold = $this->getArgument('hold'); $should_keep = $this->getArgument('keep-branches'); $revision = $this->getArgument('revision'); $strategy = $this->getArgument('strategy'); $land_engine ->setViewer($this->getViewer()) ->setWorkflow($this) ->setLogEngine($this->getLogEngine()) ->setSourceRefs($source_refs) ->setShouldHold($should_hold) ->setShouldKeep($should_keep) ->setStrategyArgument($strategy) ->setShouldPreview($is_preview) ->setOntoRemoteArgument($onto_remote_arg) ->setOntoArguments($onto_args) ->setIntoRemoteArgument($into_remote) ->setIntoEmptyArgument($into_empty) ->setIntoLocalArgument($into_local) ->setIntoArgument($into) ->setIsIncremental($is_incremental) ->setRevisionSymbol($revision); $land_engine->execute(); } }