mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 08:12:40 +01:00
Allow users to save prompt responses in "arc" workflows
Summary: Ref T13546. Permit users to answer "y*" to mean "y, and don't ask me again". Test Plan: Answered "y*" to some prompts, re-ran workflows, got auto-responses. Maniphest Tasks: T13546 Differential Revision: https://secure.phabricator.com/D21331
This commit is contained in:
parent
f3f31155b7
commit
c5192bde34
10 changed files with 377 additions and 48 deletions
|
@ -396,6 +396,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase.php',
|
'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase.php',
|
||||||
'ArcanistProjectConfigurationSource' => 'config/source/ArcanistProjectConfigurationSource.php',
|
'ArcanistProjectConfigurationSource' => 'config/source/ArcanistProjectConfigurationSource.php',
|
||||||
'ArcanistPrompt' => 'toolset/ArcanistPrompt.php',
|
'ArcanistPrompt' => 'toolset/ArcanistPrompt.php',
|
||||||
|
'ArcanistPromptResponse' => 'toolset/ArcanistPromptResponse.php',
|
||||||
|
'ArcanistPromptsConfigOption' => 'config/option/ArcanistPromptsConfigOption.php',
|
||||||
'ArcanistPromptsWorkflow' => 'toolset/workflow/ArcanistPromptsWorkflow.php',
|
'ArcanistPromptsWorkflow' => 'toolset/workflow/ArcanistPromptsWorkflow.php',
|
||||||
'ArcanistPublicPropertyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPublicPropertyXHPASTLinterRule.php',
|
'ArcanistPublicPropertyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPublicPropertyXHPASTLinterRule.php',
|
||||||
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPublicPropertyXHPASTLinterRuleTestCase.php',
|
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPublicPropertyXHPASTLinterRuleTestCase.php',
|
||||||
|
@ -1420,6 +1422,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistProjectConfigurationSource' => 'ArcanistWorkingCopyConfigurationSource',
|
'ArcanistProjectConfigurationSource' => 'ArcanistWorkingCopyConfigurationSource',
|
||||||
'ArcanistPrompt' => 'Phobject',
|
'ArcanistPrompt' => 'Phobject',
|
||||||
|
'ArcanistPromptResponse' => 'Phobject',
|
||||||
|
'ArcanistPromptsConfigOption' => 'ArcanistMultiSourceConfigOption',
|
||||||
'ArcanistPromptsWorkflow' => 'ArcanistWorkflow',
|
'ArcanistPromptsWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistPublicPropertyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistPublicPropertyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
|
|
@ -6,6 +6,7 @@ final class ArcanistArcConfigurationEngineExtension
|
||||||
const EXTENSIONKEY = 'arc';
|
const EXTENSIONKEY = 'arc';
|
||||||
|
|
||||||
const KEY_ALIASES = 'aliases';
|
const KEY_ALIASES = 'aliases';
|
||||||
|
const KEY_PROMPTS = 'prompts';
|
||||||
|
|
||||||
public function newConfigurationOptions() {
|
public function newConfigurationOptions() {
|
||||||
// TOOLSETS: Restore "load", and maybe this other stuff.
|
// TOOLSETS: Restore "load", and maybe this other stuff.
|
||||||
|
@ -113,6 +114,14 @@ final class ArcanistArcConfigurationEngineExtension
|
||||||
pht(
|
pht(
|
||||||
'Configured command aliases. Use the "alias" workflow to define '.
|
'Configured command aliases. Use the "alias" workflow to define '.
|
||||||
'aliases.')),
|
'aliases.')),
|
||||||
|
id(new ArcanistPromptsConfigOption())
|
||||||
|
->setKey(self::KEY_PROMPTS)
|
||||||
|
->setDefaultValue(array())
|
||||||
|
->setSummary(pht('List of prompt responses.'))
|
||||||
|
->setHelp(
|
||||||
|
pht(
|
||||||
|
'Configured prompt aliases. Use the "prompts" workflow to '.
|
||||||
|
'show prompts and responses.')),
|
||||||
id(new ArcanistStringListConfigOption())
|
id(new ArcanistStringListConfigOption())
|
||||||
->setKey('arc.land.onto')
|
->setKey('arc.land.onto')
|
||||||
->setDefaultValue(array())
|
->setDefaultValue(array())
|
||||||
|
|
51
src/config/option/ArcanistPromptsConfigOption.php
Normal file
51
src/config/option/ArcanistPromptsConfigOption.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistPromptsConfigOption
|
||||||
|
extends ArcanistMultiSourceConfigOption {
|
||||||
|
|
||||||
|
public function getType() {
|
||||||
|
return 'map<string, prompt>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValueFromStorageValue($value) {
|
||||||
|
if (!is_array($value)) {
|
||||||
|
throw new Exception(pht('Expected a list!'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!phutil_is_natural_list($value)) {
|
||||||
|
throw new Exception(pht('Expected a natural list!'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$responses = array();
|
||||||
|
foreach ($value as $spec) {
|
||||||
|
$responses[] = ArcanistPromptResponse::newFromConfig($spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function didReadStorageValueList(array $list) {
|
||||||
|
assert_instances_of($list, 'ArcanistConfigurationSourceValue');
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($list as $spec) {
|
||||||
|
$source = $spec->getConfigurationSource();
|
||||||
|
$value = $spec->getValue();
|
||||||
|
|
||||||
|
$value->setConfigurationSource($source);
|
||||||
|
|
||||||
|
$results[] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayValueFromValue($value) {
|
||||||
|
return pht('Use the "prompts" workflow to review prompt responses.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStorageValueFromValue($value) {
|
||||||
|
return mpull($value, 'getStorageDictionary');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ abstract class ArcanistConfigurationSource
|
||||||
extends Phobject {
|
extends Phobject {
|
||||||
|
|
||||||
const SCOPE_USER = 'user';
|
const SCOPE_USER = 'user';
|
||||||
|
const SCOPE_WORKING_COPY = 'working-copy';
|
||||||
|
|
||||||
abstract public function getSourceDisplayName();
|
abstract public function getSourceDisplayName();
|
||||||
abstract public function getAllKeys();
|
abstract public function getAllKeys();
|
||||||
|
|
|
@ -7,4 +7,12 @@ final class ArcanistLocalConfigurationSource
|
||||||
return pht('Local Config File');
|
return pht('Local Config File');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isWritableConfigurationSource() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfigurationSourceScope() {
|
||||||
|
return ArcanistConfigurationSource::SCOPE_WORKING_COPY;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -884,7 +884,6 @@ final class ArcanistRuntime {
|
||||||
$legacy[] = new ArcanistGetConfigWorkflow();
|
$legacy[] = new ArcanistGetConfigWorkflow();
|
||||||
$legacy[] = new ArcanistSetConfigWorkflow();
|
$legacy[] = new ArcanistSetConfigWorkflow();
|
||||||
$legacy[] = new ArcanistInstallCertificateWorkflow();
|
$legacy[] = new ArcanistInstallCertificateWorkflow();
|
||||||
$legacy[] = new ArcanistLandWorkflow();
|
|
||||||
$legacy[] = new ArcanistLintersWorkflow();
|
$legacy[] = new ArcanistLintersWorkflow();
|
||||||
$legacy[] = new ArcanistLintWorkflow();
|
$legacy[] = new ArcanistLintWorkflow();
|
||||||
$legacy[] = new ArcanistListWorkflow();
|
$legacy[] = new ArcanistListWorkflow();
|
||||||
|
|
|
@ -70,8 +70,10 @@ final class ArcanistPrompt
|
||||||
$this->getKey()));
|
$this->getKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$options = '[y/N]';
|
$options = '[y/N/?]';
|
||||||
$default = 'N';
|
$default = 'n';
|
||||||
|
|
||||||
|
$saved_response = $this->getSavedResponse();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
phutil_console_require_tty();
|
phutil_console_require_tty();
|
||||||
|
@ -101,54 +103,78 @@ final class ArcanistPrompt
|
||||||
echo "\n";
|
echo "\n";
|
||||||
|
|
||||||
$result = null;
|
$result = null;
|
||||||
|
$is_saved = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
echo tsprintf(
|
if ($saved_response !== null) {
|
||||||
'**<bg:cyan> %s </bg>** %s %s ',
|
$is_saved = true;
|
||||||
'>>>',
|
|
||||||
$query,
|
|
||||||
$options);
|
|
||||||
|
|
||||||
while (true) {
|
$response = $saved_response;
|
||||||
$read = array($stdin);
|
$saved_response = null;
|
||||||
$write = array();
|
} else {
|
||||||
$except = array();
|
echo tsprintf(
|
||||||
|
'**<bg:cyan> %s </bg>** %s %s ',
|
||||||
|
'>>>',
|
||||||
|
$query,
|
||||||
|
$options);
|
||||||
|
|
||||||
$ok = @stream_select($read, $write, $except, 1);
|
|
||||||
if ($ok === false) {
|
|
||||||
// NOTE: We may be interrupted by a system call, particularly if
|
|
||||||
// the window is resized while a prompt is shown and the terminal
|
|
||||||
// sends SIGWINCH.
|
|
||||||
|
|
||||||
// If we are, just continue below and try to read from stdin. If
|
|
||||||
// we were interrupted, we should read nothing and continue
|
|
||||||
// normally. If the pipe is broken, the read should fail.
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = '';
|
|
||||||
while (true) {
|
while (true) {
|
||||||
$bytes = fread($stdin, 8192);
|
$is_saved = false;
|
||||||
if ($bytes === false) {
|
|
||||||
throw new Exception(
|
$read = array($stdin);
|
||||||
pht('fread() from stdin failed with an error.'));
|
$write = array();
|
||||||
|
$except = array();
|
||||||
|
|
||||||
|
$ok = @stream_select($read, $write, $except, 1);
|
||||||
|
if ($ok === false) {
|
||||||
|
// NOTE: We may be interrupted by a system call, particularly if
|
||||||
|
// the window is resized while a prompt is shown and the terminal
|
||||||
|
// sends SIGWINCH.
|
||||||
|
|
||||||
|
// If we are, just continue below and try to read from stdin. If
|
||||||
|
// we were interrupted, we should read nothing and continue
|
||||||
|
// normally. If the pipe is broken, the read should fail.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strlen($bytes)) {
|
$response = '';
|
||||||
break;
|
while (true) {
|
||||||
|
$bytes = fread($stdin, 8192);
|
||||||
|
if ($bytes === false) {
|
||||||
|
throw new Exception(
|
||||||
|
pht('fread() from stdin failed with an error.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strlen($bytes)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response .= $bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
$response .= $bytes;
|
if (!strlen($response)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$response = trim($response);
|
||||||
if (!strlen($response)) {
|
if (!strlen($response)) {
|
||||||
continue;
|
$response = $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = trim($response);
|
$save_scope = null;
|
||||||
if (!strlen($response)) {
|
if (!$is_saved) {
|
||||||
$response = $default;
|
$matches = null;
|
||||||
|
if (preg_match('(^(.*)([!*])\z)', $response, $matches)) {
|
||||||
|
$response = $matches[1];
|
||||||
|
|
||||||
|
if ($matches[2] === '*') {
|
||||||
|
$save_scope = ArcanistConfigurationSource::SCOPE_USER;
|
||||||
|
} else {
|
||||||
|
$save_scope = ArcanistConfigurationSource::SCOPE_WORKING_COPY;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phutil_utf8_strtolower($response) == 'y') {
|
if (phutil_utf8_strtolower($response) == 'y') {
|
||||||
|
@ -160,12 +186,127 @@ final class ArcanistPrompt
|
||||||
$result = false;
|
$result = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (phutil_utf8_strtolower($response) == '?') {
|
||||||
|
echo tsprintf(
|
||||||
|
"\n<bg:green>** %s **</bg> **%s**\n\n",
|
||||||
|
pht('PROMPT'),
|
||||||
|
$this->getKey());
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
$this->getDescription());
|
||||||
|
|
||||||
|
echo tsprintf("\n");
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'The default response to this prompt is "%s".',
|
||||||
|
$default));
|
||||||
|
|
||||||
|
echo tsprintf("\n");
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%?\n",
|
||||||
|
pht(
|
||||||
|
'Use "*" after a response to save it in user configuration.'));
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%?\n",
|
||||||
|
pht(
|
||||||
|
'Use "!" after a response to save it in working copy '.
|
||||||
|
'configuration.'));
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%?\n",
|
||||||
|
pht(
|
||||||
|
'Run "arc help prompts" for detailed help on configuring '.
|
||||||
|
'responses.'));
|
||||||
|
|
||||||
|
echo tsprintf("\n");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($save_scope !== null) {
|
||||||
|
$this->saveResponse($save_scope, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($is_saved) {
|
||||||
|
echo tsprintf(
|
||||||
|
"<bg:cyan>** %s **</bg> %s **<%s>**\n".
|
||||||
|
"<bg:cyan>** %s **</bg> (%s)\n\n",
|
||||||
|
'>>>',
|
||||||
|
$query,
|
||||||
|
$response,
|
||||||
|
'>>>',
|
||||||
|
pht(
|
||||||
|
'Using saved response to prompt "%s".',
|
||||||
|
$this->getKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
throw new ArcanistUserAbortException();
|
throw new ArcanistUserAbortException();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSavedResponse() {
|
||||||
|
$config_key = ArcanistArcConfigurationEngineExtension::KEY_PROMPTS;
|
||||||
|
$workflow = $this->getWorkflow();
|
||||||
|
|
||||||
|
$config = $workflow->getConfig($config_key);
|
||||||
|
|
||||||
|
$prompt_key = $this->getKey();
|
||||||
|
|
||||||
|
$prompt_response = null;
|
||||||
|
foreach ($config as $response) {
|
||||||
|
if ($response->getPrompt() === $prompt_key) {
|
||||||
|
$prompt_response = $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prompt_response === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $prompt_response->getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveResponse($scope, $response_value) {
|
||||||
|
$config_key = ArcanistArcConfigurationEngineExtension::KEY_PROMPTS;
|
||||||
|
$workflow = $this->getWorkflow();
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"<bg:green>** %s **</bg> %s\n",
|
||||||
|
pht('SAVE PROMPT'),
|
||||||
|
pht(
|
||||||
|
'Saving response "%s" to prompt "%s".',
|
||||||
|
$response_value,
|
||||||
|
$this->getKey()));
|
||||||
|
|
||||||
|
$source_list = $workflow->getConfigurationSourceList();
|
||||||
|
$source = $source_list->getWritableSourceFromScope($scope);
|
||||||
|
|
||||||
|
$response_list = $source_list->getConfigFromScopes(
|
||||||
|
$config_key,
|
||||||
|
array($scope));
|
||||||
|
|
||||||
|
foreach ($response_list as $key => $response) {
|
||||||
|
if ($response->getPrompt() === $this->getKey()) {
|
||||||
|
unset($response_list[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response_value !== null) {
|
||||||
|
$response_list[] = id(new ArcanistPromptResponse())
|
||||||
|
->setPrompt($this->getKey())
|
||||||
|
->setResponse($response_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$option = $source_list->getConfigOption($config_key);
|
||||||
|
$option->writeValue($source, $response_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
59
src/toolset/ArcanistPromptResponse.php
Normal file
59
src/toolset/ArcanistPromptResponse.php
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistPromptResponse
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $prompt;
|
||||||
|
private $response;
|
||||||
|
private $configurationSource;
|
||||||
|
|
||||||
|
public static function newFromConfig($map) {
|
||||||
|
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$map,
|
||||||
|
array(
|
||||||
|
'prompt' => 'string',
|
||||||
|
'response' => 'string',
|
||||||
|
));
|
||||||
|
|
||||||
|
return id(new self())
|
||||||
|
->setPrompt($map['prompt'])
|
||||||
|
->setResponse($map['response']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStorageDictionary() {
|
||||||
|
return array(
|
||||||
|
'prompt' => $this->getPrompt(),
|
||||||
|
'response' => $this->getResponse(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPrompt($prompt) {
|
||||||
|
$this->prompt = $prompt;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrompt() {
|
||||||
|
return $this->prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setResponse($response) {
|
||||||
|
$this->response = $response;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResponse() {
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConfigurationSource(
|
||||||
|
ArcanistConfigurationSource $configuration_source) {
|
||||||
|
$this->configurationSource = $configuration_source;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConfigurationSource() {
|
||||||
|
return $this->configurationSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class ArcanistPromptsWorkflow extends ArcanistWorkflow {
|
final class ArcanistPromptsWorkflow
|
||||||
|
extends ArcanistWorkflow {
|
||||||
|
|
||||||
public function supportsToolset(ArcanistToolset $toolset) {
|
public function supportsToolset(ArcanistToolset $toolset) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -12,14 +13,34 @@ final class ArcanistPromptsWorkflow extends ArcanistWorkflow {
|
||||||
|
|
||||||
public function getWorkflowInformation() {
|
public function getWorkflowInformation() {
|
||||||
$help = pht(<<<EOTEXT
|
$help = pht(<<<EOTEXT
|
||||||
Show information about prompts a workflow may execute and configure default
|
Show information about prompts a workflow may execute, and review saved
|
||||||
responses.
|
responses.
|
||||||
|
|
||||||
**Show Prompts**
|
**Show Prompts**
|
||||||
|
|
||||||
To show possible prompts a workflow may execute, run:
|
To show possible prompts a workflow may execute, run:
|
||||||
|
|
||||||
$ arc prompts <workflow>
|
$ arc prompts __workflow__
|
||||||
|
|
||||||
|
**Saving Responses**
|
||||||
|
|
||||||
|
If you always want to answer a particular prompt in a certain way, you can
|
||||||
|
save your response to the prompt. When you encounter the prompt again, your
|
||||||
|
saved response will be used automatically.
|
||||||
|
|
||||||
|
To save a response, add "*" or "!" to the end of the response you want to save
|
||||||
|
when you answer the prompt:
|
||||||
|
|
||||||
|
- Using "*" will save the response in user configuration. In the future,
|
||||||
|
the saved answer will be used any time you encounter the prompt (in any
|
||||||
|
project).
|
||||||
|
- Using "!" will save the response in working copy configuration. In the
|
||||||
|
future, the saved answer will be used when you encounter the prompt in
|
||||||
|
the current working copy.
|
||||||
|
|
||||||
|
For example, if you would like to always answer "y" to a particular prompt,
|
||||||
|
respond with "y*" or "y!" to save your response.
|
||||||
|
|
||||||
EOTEXT
|
EOTEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -65,16 +86,51 @@ EOTEXT
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$prompts = msort($prompts, 'getKey');
|
||||||
|
|
||||||
|
$blocks = array();
|
||||||
foreach ($prompts as $prompt) {
|
foreach ($prompts as $prompt) {
|
||||||
echo tsprintf(
|
$block = array();
|
||||||
"**%s**\n",
|
$block[] = tsprintf(
|
||||||
|
"<bg:green>** %s **</bg> **%s**\n\n",
|
||||||
|
pht('PROMPT'),
|
||||||
$prompt->getKey());
|
$prompt->getKey());
|
||||||
echo tsprintf(
|
$block[] = tsprintf(
|
||||||
"%s\n",
|
"%W\n",
|
||||||
$prompt->getDescription());
|
$prompt->getDescription());
|
||||||
|
|
||||||
|
$responses = $this->getSavedResponses($prompt->getKey());
|
||||||
|
if ($responses) {
|
||||||
|
$block[] = tsprintf("\n");
|
||||||
|
foreach ($responses as $response) {
|
||||||
|
$block[] = tsprintf(
|
||||||
|
" <bg:cyan>** > **</bg> %s\n",
|
||||||
|
pht(
|
||||||
|
'You have saved the response "%s" to this prompt.',
|
||||||
|
$response->getResponse()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$blocks[] = $block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
echo tsprintf('%B', phutil_glue($blocks, tsprintf("\n")));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getSavedResponses($prompt_key) {
|
||||||
|
$config_key = ArcanistArcConfigurationEngineExtension::KEY_PROMPTS;
|
||||||
|
$config = $this->getConfig($config_key);
|
||||||
|
|
||||||
|
$responses = array();
|
||||||
|
foreach ($config as $response) {
|
||||||
|
if ($response->getPrompt() === $prompt_key) {
|
||||||
|
$responses[] = $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $responses;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,12 +237,13 @@ EOTEXT
|
||||||
$this->newPrompt('arc.land.confirm')
|
$this->newPrompt('arc.land.confirm')
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht(
|
pht(
|
||||||
'Confirms that the correct changes have been selected.')),
|
'Confirms that the correct changes have been selected to '.
|
||||||
|
'land.')),
|
||||||
$this->newPrompt('arc.land.implicit')
|
$this->newPrompt('arc.land.implicit')
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht(
|
pht(
|
||||||
'Confirms that local commits which are not associated with '.
|
'Confirms that local commits which are not associated with '.
|
||||||
'a revision should land.')),
|
'a revision have been associated correctly and should land.')),
|
||||||
$this->newPrompt('arc.land.unauthored')
|
$this->newPrompt('arc.land.unauthored')
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht(
|
pht(
|
||||||
|
@ -267,11 +268,11 @@ EOTEXT
|
||||||
$this->newPrompt('arc.land.failed-builds')
|
$this->newPrompt('arc.land.failed-builds')
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht(
|
pht(
|
||||||
'Confirms that revisions with failed builds.')),
|
'Confirms that revisions with failed builds should land.')),
|
||||||
$this->newPrompt('arc.land.ongoing-builds')
|
$this->newPrompt('arc.land.ongoing-builds')
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht(
|
pht(
|
||||||
'Confirms that revisions with ongoing builds.')),
|
'Confirms that revisions with ongoing builds should land.')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue