mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-10 00:42:40 +01:00
Remove "backout", "close", "flag", "start", "stop", "time", and "revert" workflows
Summary: Ref T13490. These workflows don't seem worth the maintenance cost, see T13488 for discussion. Test Plan: Grepped for methods which looked like they might only be called by these flows, only dug up the backout stuff. Maniphest Tasks: T13490 Differential Revision: https://secure.phabricator.com/D21100
This commit is contained in:
parent
4719341c27
commit
196f8f54ce
11 changed files with 0 additions and 981 deletions
|
@ -39,7 +39,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistArraySeparatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistArraySeparatorXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistArrayValueXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArrayValueXHPASTLinterRule.php',
|
||||
'ArcanistArrayValueXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistArrayValueXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistBackoutWorkflow' => 'workflow/ArcanistBackoutWorkflow.php',
|
||||
'ArcanistBaseCommitParser' => 'parser/ArcanistBaseCommitParser.php',
|
||||
'ArcanistBaseCommitParserTestCase' => 'parser/__tests__/ArcanistBaseCommitParserTestCase.php',
|
||||
'ArcanistBaseXHPASTLinter' => 'lint/linter/ArcanistBaseXHPASTLinter.php',
|
||||
|
@ -91,7 +90,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistClassNameLiteralXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistClassNameLiteralXHPASTLinterRule.php',
|
||||
'ArcanistClassNameLiteralXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistClassNameLiteralXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistCloseRevisionWorkflow' => 'workflow/ArcanistCloseRevisionWorkflow.php',
|
||||
'ArcanistCloseWorkflow' => 'workflow/ArcanistCloseWorkflow.php',
|
||||
'ArcanistClosureLinter' => 'lint/linter/ArcanistClosureLinter.php',
|
||||
'ArcanistClosureLinterTestCase' => 'lint/linter/__tests__/ArcanistClosureLinterTestCase.php',
|
||||
'ArcanistCoffeeLintLinter' => 'lint/linter/ArcanistCoffeeLintLinter.php',
|
||||
|
@ -200,7 +198,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistFilesystemAPI' => 'repository/api/ArcanistFilesystemAPI.php',
|
||||
'ArcanistFilesystemConfigurationSource' => 'config/source/ArcanistFilesystemConfigurationSource.php',
|
||||
'ArcanistFilesystemWorkingCopy' => 'workingcopy/ArcanistFilesystemWorkingCopy.php',
|
||||
'ArcanistFlagWorkflow' => 'workflow/ArcanistFlagWorkflow.php',
|
||||
'ArcanistFlake8Linter' => 'lint/linter/ArcanistFlake8Linter.php',
|
||||
'ArcanistFlake8LinterTestCase' => 'lint/linter/__tests__/ArcanistFlake8LinterTestCase.php',
|
||||
'ArcanistFormattedStringXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php',
|
||||
|
@ -371,7 +368,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistPhpcsLinter' => 'lint/linter/ArcanistPhpcsLinter.php',
|
||||
'ArcanistPhpcsLinterTestCase' => 'lint/linter/__tests__/ArcanistPhpcsLinterTestCase.php',
|
||||
'ArcanistPhpunitTestResultParser' => 'unit/parser/ArcanistPhpunitTestResultParser.php',
|
||||
'ArcanistPhrequentWorkflow' => 'workflow/ArcanistPhrequentWorkflow.php',
|
||||
'ArcanistPhutilLibraryLinter' => 'lint/linter/ArcanistPhutilLibraryLinter.php',
|
||||
'ArcanistPhutilWorkflow' => 'toolset/ArcanistPhutilWorkflow.php',
|
||||
'ArcanistPhutilXHPASTLinterStandard' => 'lint/linter/standards/phutil/ArcanistPhutilXHPASTLinterStandard.php',
|
||||
|
@ -402,7 +398,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistReusedIteratorReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedIteratorReferenceXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistReusedIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorXHPASTLinterRule.php',
|
||||
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedIteratorXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php',
|
||||
'ArcanistRevisionCommitMessageHardpointQuery' => 'ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php',
|
||||
'ArcanistRevisionRef' => 'ref/revision/ArcanistRevisionRef.php',
|
||||
'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php',
|
||||
|
@ -434,10 +429,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistSlownessXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSlownessXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistSpellingLinter' => 'lint/linter/ArcanistSpellingLinter.php',
|
||||
'ArcanistSpellingLinterTestCase' => 'lint/linter/__tests__/ArcanistSpellingLinterTestCase.php',
|
||||
'ArcanistStartWorkflow' => 'workflow/ArcanistStartWorkflow.php',
|
||||
'ArcanistStaticThisXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistStaticThisXHPASTLinterRule.php',
|
||||
'ArcanistStaticThisXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistStaticThisXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistStopWorkflow' => 'workflow/ArcanistStopWorkflow.php',
|
||||
'ArcanistStringConfigOption' => 'config/option/ArcanistStringConfigOption.php',
|
||||
'ArcanistSubversionAPI' => 'repository/api/ArcanistSubversionAPI.php',
|
||||
'ArcanistSubversionWorkingCopy' => 'workingcopy/ArcanistSubversionWorkingCopy.php',
|
||||
|
@ -456,7 +449,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistTextLinterTestCase' => 'lint/linter/__tests__/ArcanistTextLinterTestCase.php',
|
||||
'ArcanistThisReassignmentXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistThisReassignmentXHPASTLinterRule.php',
|
||||
'ArcanistThisReassignmentXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistThisReassignmentXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistTimeWorkflow' => 'workflow/ArcanistTimeWorkflow.php',
|
||||
'ArcanistToStringExceptionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistToStringExceptionXHPASTLinterRule.php',
|
||||
'ArcanistToStringExceptionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistToStringExceptionXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistTodoCommentXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTodoCommentXHPASTLinterRule.php',
|
||||
|
@ -1024,7 +1016,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistArraySeparatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistArrayValueXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistArrayValueXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistBackoutWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistBaseCommitParser' => 'Phobject',
|
||||
'ArcanistBaseCommitParserTestCase' => 'PhutilTestCase',
|
||||
'ArcanistBaseXHPASTLinter' => 'ArcanistFutureLinter',
|
||||
|
@ -1076,7 +1067,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistClassNameLiteralXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistClassNameLiteralXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistCloseRevisionWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistCloseWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistClosureLinter' => 'ArcanistExternalLinter',
|
||||
'ArcanistClosureLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistCoffeeLintLinter' => 'ArcanistExternalLinter',
|
||||
|
@ -1190,7 +1180,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistFilesystemAPI' => 'ArcanistRepositoryAPI',
|
||||
'ArcanistFilesystemConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
|
||||
'ArcanistFilesystemWorkingCopy' => 'ArcanistWorkingCopy',
|
||||
'ArcanistFlagWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistFlake8Linter' => 'ArcanistExternalLinter',
|
||||
'ArcanistFlake8LinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistFormattedStringXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
|
@ -1361,7 +1350,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistPhpcsLinter' => 'ArcanistExternalLinter',
|
||||
'ArcanistPhpcsLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistPhpunitTestResultParser' => 'ArcanistTestResultParser',
|
||||
'ArcanistPhrequentWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistPhutilLibraryLinter' => 'ArcanistLinter',
|
||||
'ArcanistPhutilWorkflow' => 'PhutilArgumentWorkflow',
|
||||
'ArcanistPhutilXHPASTLinterStandard' => 'ArcanistLinterStandard',
|
||||
|
@ -1392,7 +1380,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistReusedIteratorReferenceXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistReusedIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistRevertWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistRevisionCommitMessageHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
|
||||
'ArcanistRevisionRef' => array(
|
||||
'ArcanistRef',
|
||||
|
@ -1426,10 +1413,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistSlownessXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistSpellingLinter' => 'ArcanistLinter',
|
||||
'ArcanistSpellingLinterTestCase' => 'ArcanistLinterTestCase',
|
||||
'ArcanistStartWorkflow' => 'ArcanistPhrequentWorkflow',
|
||||
'ArcanistStaticThisXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistStaticThisXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistStopWorkflow' => 'ArcanistPhrequentWorkflow',
|
||||
'ArcanistStringConfigOption' => 'ArcanistScalarConfigOption',
|
||||
'ArcanistSubversionAPI' => 'ArcanistRepositoryAPI',
|
||||
'ArcanistSubversionWorkingCopy' => 'ArcanistWorkingCopy',
|
||||
|
@ -1447,7 +1432,6 @@ phutil_register_library_map(array(
|
|||
'ArcanistTextLinterTestCase' => 'ArcanistLinterTestCase',
|
||||
'ArcanistThisReassignmentXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistThisReassignmentXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistTimeWorkflow' => 'ArcanistPhrequentWorkflow',
|
||||
'ArcanistToStringExceptionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistToStringExceptionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistTodoCommentXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
|
|
|
@ -1278,19 +1278,6 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
|
|||
return trim($summary);
|
||||
}
|
||||
|
||||
public function backoutCommit($commit_hash) {
|
||||
$this->execxLocal('revert %s -n --no-edit', $commit_hash);
|
||||
$this->reloadWorkingCopy();
|
||||
if (!$this->getUncommittedStatus()) {
|
||||
throw new ArcanistUsageException(
|
||||
pht('%s has already been reverted.', $commit_hash));
|
||||
}
|
||||
}
|
||||
|
||||
public function getBackoutMessage($commit_hash) {
|
||||
return pht('This reverts commit %s.', $commit_hash);
|
||||
}
|
||||
|
||||
public function isGitSubversionRepo() {
|
||||
return Filesystem::pathExists($this->getPath('.git/svn'));
|
||||
}
|
||||
|
|
|
@ -797,19 +797,6 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
|||
return trim($summary);
|
||||
}
|
||||
|
||||
public function backoutCommit($commit_hash) {
|
||||
$this->execxLocal('backout -r %s', $commit_hash);
|
||||
$this->reloadWorkingCopy();
|
||||
if (!$this->getUncommittedStatus()) {
|
||||
throw new ArcanistUsageException(
|
||||
pht('%s has already been reverted.', $commit_hash));
|
||||
}
|
||||
}
|
||||
|
||||
public function getBackoutMessage($commit_hash) {
|
||||
return pht('Backed out changeset %s,', $commit_hash);
|
||||
}
|
||||
|
||||
public function resolveBaseCommitRule($rule, $source) {
|
||||
list($type, $name) = explode(':', $rule, 2);
|
||||
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Runs git revert and assigns a high priority task to original author.
|
||||
*/
|
||||
final class ArcanistBackoutWorkflow extends ArcanistWorkflow {
|
||||
|
||||
private $console;
|
||||
private $conduit;
|
||||
private $revision;
|
||||
|
||||
public function getWorkflowName() {
|
||||
return 'backout';
|
||||
}
|
||||
|
||||
public function getCommandSynopses() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**backout**
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
Reverts/backouts on a previous commit. Supports: git, hg
|
||||
Command is used like this: arc backout <commithash> | <diff revision>
|
||||
Entering a differential revision will only work if there is only one commit
|
||||
associated with the revision. This requires your working copy is up to date
|
||||
and that the commit exists in the working copy.
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getArguments() {
|
||||
return array(
|
||||
'*' => 'input',
|
||||
);
|
||||
}
|
||||
|
||||
public function requiresWorkingCopy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requiresRepositoryAPI() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requiresAuthentication() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a differential revision ID, fetches the commit ID.
|
||||
*/
|
||||
private function getCommitIDFromRevisionID($revision_id) {
|
||||
$conduit = $this->getConduit();
|
||||
$revisions = $conduit->callMethodSynchronous(
|
||||
'differential.query',
|
||||
array(
|
||||
'ids' => array($revision_id),
|
||||
));
|
||||
if (!$revisions) {
|
||||
throw new ArcanistUsageException(
|
||||
pht('The revision you provided does not exist!'));
|
||||
}
|
||||
$revision = $revisions[0];
|
||||
$commits = $revision['commits'];
|
||||
if (!$commits) {
|
||||
throw new ArcanistUsageException(
|
||||
pht('This revision has not been committed yet!'));
|
||||
} else if (count($commits) > 1) {
|
||||
throw new ArcanistUsageException(
|
||||
pht('The revision you provided has multiple commits!'));
|
||||
}
|
||||
$commit_phid = $commits[0];
|
||||
$commit = $conduit->callMethodSynchronous(
|
||||
'phid.query',
|
||||
array(
|
||||
'phids' => array($commit_phid),
|
||||
));
|
||||
$commit_id = $commit[$commit_phid]['name'];
|
||||
return $commit_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an array of commit info provided a Commit_id in the form of
|
||||
* rE123456 (not local commit hash).
|
||||
*/
|
||||
private function getDiffusionCommit($commit_id) {
|
||||
$result = $this->getConduit()->callMethodSynchronous(
|
||||
'diffusion.querycommits',
|
||||
array(
|
||||
'names' => array($commit_id),
|
||||
));
|
||||
$phid = idx($result['identifierMap'], $commit_id);
|
||||
// This commit was not found in Diffusion
|
||||
if (!$phid) {
|
||||
return null;
|
||||
}
|
||||
$commit = $result['data'][$phid];
|
||||
return $commit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves default template from differential and pre-fills info.
|
||||
*/
|
||||
private function buildCommitMessage($commit_hash) {
|
||||
$conduit = $this->getConduit();
|
||||
$repository_api = $this->getRepositoryAPI();
|
||||
|
||||
$summary = $repository_api->getBackoutMessage($commit_hash);
|
||||
$fields = array(
|
||||
'summary' => $summary,
|
||||
'testPlan' => 'revert-hammer',
|
||||
);
|
||||
$template = $conduit->callMethodSynchronous(
|
||||
'differential.getcommitmessage',
|
||||
array(
|
||||
'revision_id' => null,
|
||||
'edit' => 'create',
|
||||
'fields' => $fields,
|
||||
));
|
||||
$template = $this->newInteractiveEditor($template)
|
||||
->setName('new-commit')
|
||||
->editInteractively();
|
||||
|
||||
$template = ArcanistCommentRemover::removeComments($template);
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
public function getSupportedRevisionControlSystems() {
|
||||
return array('git', 'hg');
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the backout/revert of a revision and creates a commit.
|
||||
*/
|
||||
public function run() {
|
||||
$console = PhutilConsole::getConsole();
|
||||
$conduit = $this->getConduit();
|
||||
$repository_api = $this->getRepositoryAPI();
|
||||
|
||||
$is_git_svn = $repository_api instanceof ArcanistGitAPI &&
|
||||
$repository_api->isGitSubversionRepo();
|
||||
$is_hg_svn = $repository_api instanceof ArcanistMercurialAPI &&
|
||||
$repository_api->isHgSubversionRepo();
|
||||
$revision_id = null;
|
||||
|
||||
$console->writeOut(pht('Starting backout.')."\n");
|
||||
$input = $this->getArgument('input');
|
||||
if (!$input || count($input) != 1) {
|
||||
throw new ArcanistUsageException(
|
||||
pht('You must specify one commit to backout!'));
|
||||
}
|
||||
|
||||
// Input looks like a Differential revision, so
|
||||
// we try to find the commit attached to it
|
||||
$matches = array();
|
||||
if (preg_match('/^D(\d+)$/i', $input[0], $matches)) {
|
||||
$revision_id = $matches[1];
|
||||
$commit_id = $this->getCommitIDFromRevisionID($revision_id);
|
||||
$commit = $this->getDiffusionCommit($commit_id);
|
||||
$commit_hash = $commit['identifier'];
|
||||
// Convert commit hash from SVN to Git/HG (for FB case)
|
||||
if ($is_git_svn || $is_hg_svn) {
|
||||
$commit_hash = $repository_api
|
||||
->getHashFromFromSVNRevisionNumber($commit_hash);
|
||||
}
|
||||
} else {
|
||||
// Assume input is a commit hash
|
||||
$commit_hash = $input[0];
|
||||
}
|
||||
if (!$repository_api->hasLocalCommit($commit_hash)) {
|
||||
throw new ArcanistUsageException(
|
||||
pht('Invalid commit provided or does not exist in the working copy!'));
|
||||
}
|
||||
|
||||
// Run 'backout'.
|
||||
$subject = $repository_api->getCommitSummary($commit_hash);
|
||||
$console->writeOut(
|
||||
pht('Backing out commit %s %s', $commit_hash, $subject)."\n");
|
||||
|
||||
$repository_api->backoutCommit($commit_hash);
|
||||
|
||||
// Create commit message and execute the commit
|
||||
$message = $this->buildCommitMessage($commit_hash);
|
||||
$repository_api->doCommit($message);
|
||||
$console->writeOut("%s\n",
|
||||
pht('Double-check the commit and push when ready.'));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Close a task.
|
||||
*/
|
||||
final class ArcanistCloseWorkflow extends ArcanistWorkflow {
|
||||
|
||||
private $tasks;
|
||||
private $statusOptions;
|
||||
private $statusData;
|
||||
|
||||
private function loadStatusData() {
|
||||
$this->statusData = $this->getConduit()->callMethodSynchronous(
|
||||
'maniphest.querystatuses',
|
||||
array());
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getStatusOptions() {
|
||||
if ($this->statusData === null) {
|
||||
throw new PhutilInvalidStateException('loadStatusData');
|
||||
}
|
||||
return idx($this->statusData, 'statusMap');
|
||||
}
|
||||
private function getDefaultClosedStatus() {
|
||||
if ($this->statusData === null) {
|
||||
throw new PhutilInvalidStateException('loadStatusData');
|
||||
}
|
||||
return idx($this->statusData, 'defaultClosedStatus');
|
||||
}
|
||||
|
||||
public function getWorkflowName() {
|
||||
return 'close';
|
||||
}
|
||||
|
||||
public function getCommandSynopses() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**close** __task_id__ [__options__]
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
Close a task or otherwise update its status.
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function requiresConduit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requiresRepositoryAPI() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresAuthentication() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function getArguments() {
|
||||
return array(
|
||||
'*' => 'task_id',
|
||||
'message' => array(
|
||||
'short' => 'm',
|
||||
'param' => 'comment',
|
||||
'help' => pht('Provide a comment with your status change.'),
|
||||
),
|
||||
'status' => array(
|
||||
'param' => 'status',
|
||||
'short' => 's',
|
||||
'help' => pht(
|
||||
'Specify a new status. Valid status options can be '.
|
||||
'seen with the `%s` argument.',
|
||||
'list-statuses'),
|
||||
),
|
||||
'list-statuses' => array(
|
||||
'help' => pht('Show available status options and exit.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function run() {
|
||||
$this->loadStatusData();
|
||||
$list_statuses = $this->getArgument('list-statuses');
|
||||
if ($list_statuses) {
|
||||
echo phutil_console_format(
|
||||
"%s\n",
|
||||
pht(
|
||||
"Valid status options are:\n\t%s",
|
||||
implode(', ', $this->getStatusOptions())));
|
||||
return 0;
|
||||
}
|
||||
$ids = $this->getArgument('task_id');
|
||||
$message = $this->getArgument('message');
|
||||
$status = strtolower($this->getArgument('status'));
|
||||
|
||||
$status_options = $this->getStatusOptions();
|
||||
if (!isset($status) || $status == '') {
|
||||
$status = $this->getDefaultClosedStatus();
|
||||
}
|
||||
|
||||
if (!isset($status_options[$status])) {
|
||||
$options = array_keys($status_options);
|
||||
$last = array_pop($options);
|
||||
echo pht(
|
||||
"Invalid status %s, valid options are %s, or %s.\n",
|
||||
$status,
|
||||
implode(', ', $options),
|
||||
$last);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($ids as $id) {
|
||||
if (!preg_match('/^T?\d+$/', $id)) {
|
||||
echo pht('Invalid Task ID: %s.', $id)."\n";
|
||||
return 1;
|
||||
}
|
||||
$id = ltrim($id, 'T');
|
||||
$result = $this->closeTask($id, $status, $message);
|
||||
$current_status = $status_options[$status];
|
||||
if ($result) {
|
||||
echo pht(
|
||||
"%s's status is now set to %s.\n",
|
||||
"T{$id}",
|
||||
$current_status);
|
||||
} else {
|
||||
echo pht(
|
||||
"%s is already set to %s.\n",
|
||||
"T{$id}",
|
||||
$current_status);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function closeTask($task_id, $status, $comment = '') {
|
||||
$conduit = $this->getConduit();
|
||||
$info = $conduit->callMethodSynchronous(
|
||||
'maniphest.info',
|
||||
array(
|
||||
'task_id' => $task_id,
|
||||
));
|
||||
if ($info['status'] == $status) {
|
||||
return false;
|
||||
}
|
||||
return $conduit->callMethodSynchronous(
|
||||
'maniphest.update',
|
||||
array(
|
||||
'id' => $task_id,
|
||||
'status' => $status,
|
||||
'comments' => $comment,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistFlagWorkflow extends ArcanistWorkflow {
|
||||
|
||||
private static $colorMap = array(
|
||||
0 => 'red', // Red
|
||||
1 => 'yellow', // Orange
|
||||
2 => 'yellow', // Yellow
|
||||
3 => 'green', // Green
|
||||
4 => 'blue', // Blue
|
||||
5 => 'magenta', // Pink
|
||||
6 => 'magenta', // Purple
|
||||
7 => 'default', // Checkered
|
||||
);
|
||||
|
||||
private static $colorSpec = array(
|
||||
'red' => 0,
|
||||
'r' => 0,
|
||||
0 => 0,
|
||||
'orange' => 1,
|
||||
'o' => 1,
|
||||
1 => 1,
|
||||
'yellow' => 2,
|
||||
'y' => 2,
|
||||
2 => 2,
|
||||
'green' => 3,
|
||||
'g' => 3,
|
||||
3 => 3,
|
||||
'blue' => 4,
|
||||
'b' => 4,
|
||||
4 => 4,
|
||||
'pink' => 5,
|
||||
'p' => 5,
|
||||
5 => 5,
|
||||
'purple' => 6,
|
||||
'v' => 6,
|
||||
6 => 6,
|
||||
'checkered' => 7,
|
||||
'c' => 7,
|
||||
7 => 7,
|
||||
);
|
||||
|
||||
public function getWorkflowName() {
|
||||
return 'flag';
|
||||
}
|
||||
|
||||
public function getCommandSynopses() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**flag** [__object__ ...]
|
||||
**flag** __object__ --clear
|
||||
**flag** __object__ [--edit] [--color __color__] [--note __note__]
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
In the first form, list objects you've flagged. You can provide the
|
||||
names of one or more objects (Maniphest tasks T#\##, Differential
|
||||
revisions D###, Diffusion references rXXX???, or PHIDs PHID-XXX-???)
|
||||
to print only flags for those objects.
|
||||
|
||||
In the second form, clear an existing flag on one object.
|
||||
|
||||
In the third form, create or update a flag on one object. Color
|
||||
defaults to blue and note to empty, but if you omit both you must
|
||||
pass --edit.
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getArguments() {
|
||||
return array(
|
||||
'*' => 'objects',
|
||||
'clear' => array(
|
||||
'help' => pht('Delete the flag on an object.'),
|
||||
),
|
||||
'edit' => array(
|
||||
'help' => pht('Edit the flag on an object.'),
|
||||
),
|
||||
'color' => array(
|
||||
'param' => 'color',
|
||||
'help' => pht('Set the color of a flag.'),
|
||||
),
|
||||
'note' => array(
|
||||
'param' => 'note',
|
||||
'help' => pht('Set the note on a flag.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function requiresConduit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requiresAuthentication() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function flagWasEdited($flag, $verb) {
|
||||
$color = idx(self::$colorMap, $flag['color'], 'cyan');
|
||||
$note = $flag['note'];
|
||||
if ($note) {
|
||||
// Make sure notes that are long or have line breaks in them or
|
||||
// whatever don't mess up the formatting.
|
||||
$note = implode(' ', preg_split('/\s+/', $note));
|
||||
$note = ' ('.
|
||||
id(new PhutilUTF8StringTruncator())
|
||||
->setMaximumGlyphs(40)
|
||||
->setTerminator('...')
|
||||
->truncateString($note).
|
||||
')';
|
||||
}
|
||||
echo phutil_console_format(
|
||||
"<fg:{$color}>%s</fg> flag%s $verb!\n",
|
||||
$flag['colorName'],
|
||||
$note);
|
||||
}
|
||||
|
||||
public function run() {
|
||||
$conduit = $this->getConduit();
|
||||
$objects = $this->getArgument('objects', array());
|
||||
$phids = array();
|
||||
|
||||
$clear = $this->getArgument('clear');
|
||||
$edit = $this->getArgument('edit');
|
||||
// I don't trust PHP to distinguish 0 (red) from null.
|
||||
$color = $this->getArgument('color', -1);
|
||||
$note = $this->getArgument('note');
|
||||
$editing = $edit || ($color != -1) || $note;
|
||||
|
||||
if ($editing && $clear) {
|
||||
throw new ArcanistUsageException(
|
||||
pht("You can't both edit and clear a flag."));
|
||||
}
|
||||
if (($editing || $clear) && count($objects) != 1) {
|
||||
throw new ArcanistUsageException(pht('Specify exactly one object.'));
|
||||
}
|
||||
|
||||
if (!empty($objects)) {
|
||||
// First off, convert the passed objects to PHIDs.
|
||||
$handles = $conduit->callMethodSynchronous(
|
||||
'phid.lookup',
|
||||
array(
|
||||
'names' => $objects,
|
||||
));
|
||||
foreach ($objects as $object) {
|
||||
if (isset($handles[$object])) {
|
||||
$phids[$object] = $handles[$object]['phid'];
|
||||
} else {
|
||||
echo pht(
|
||||
"%s doesn't exist.\n",
|
||||
phutil_console_format('**%s**', $object));
|
||||
}
|
||||
}
|
||||
if (empty($phids)) {
|
||||
// flag.query treats an empty objectPHIDs parameter as "don't use this
|
||||
// constraint". However, if the user gives a list of objects but none
|
||||
// of them exist and have flags, we shouldn't dump the full list on
|
||||
// them after telling them that. Conveniently, we already told them,
|
||||
// so we can go quit now.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($clear) {
|
||||
// All right, we're going to clear a flag. First clear it. Then tell the
|
||||
// user we cleared it. Step four: profit!
|
||||
$flag = $conduit->callMethodSynchronous(
|
||||
'flag.delete',
|
||||
array(
|
||||
'objectPHID' => head($phids),
|
||||
));
|
||||
if (!$flag) {
|
||||
echo pht(
|
||||
"%s has no flag to clear.\n",
|
||||
phutil_console_format('**%s**', $object));
|
||||
} else {
|
||||
self::flagWasEdited($flag, 'deleted');
|
||||
}
|
||||
} else if ($editing) {
|
||||
// Let's set some flags. Just like Minesweeper, but less distracting.
|
||||
$flag_params = array(
|
||||
'objectPHID' => head($phids),
|
||||
);
|
||||
if (isset(self::$colorSpec[$color])) {
|
||||
$flag_params['color'] = self::$colorSpec[strtolower($color)];
|
||||
}
|
||||
if ($note) {
|
||||
$flag_params['note'] = $note;
|
||||
}
|
||||
$flag = $conduit->callMethodSynchronous(
|
||||
'flag.edit',
|
||||
$flag_params);
|
||||
self::flagWasEdited($flag, $flag['new'] ? 'created' : 'edited');
|
||||
} else {
|
||||
// Okay, list mode. Let's find the flags, which we didn't need to do
|
||||
// otherwise because Conduit does it for us.
|
||||
$flags = ipull(
|
||||
$this->getConduit()->callMethodSynchronous(
|
||||
'flag.query',
|
||||
array(
|
||||
'ownerPHIDs' => array($this->getUserPHID()),
|
||||
'objectPHIDs' => array_values($phids),
|
||||
)),
|
||||
null,
|
||||
'objectPHID');
|
||||
foreach ($phids as $object => $phid) {
|
||||
if (!isset($flags[$phid])) {
|
||||
echo pht(
|
||||
"%s has no flag.\n",
|
||||
phutil_console_format('**%s**', $object));
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($flags)) {
|
||||
// If the user passed no object names, then we should print the full
|
||||
// list, but it's empty, so tell the user they have no flags.
|
||||
// If the user passed object names, we already told them all their
|
||||
// objects are nonexistent or unflagged.
|
||||
if (empty($objects)) {
|
||||
echo pht('You have no flagged objects.')."\n";
|
||||
}
|
||||
} else {
|
||||
// Print ALL the flags. With fancy formatting. Because fancy formatting
|
||||
// is _cool_.
|
||||
$name_len = 1 + max(array_map('strlen', ipull($flags, 'colorName')));
|
||||
foreach ($flags as $flag) {
|
||||
$color = idx(self::$colorMap, $flag['color'], 'cyan');
|
||||
echo phutil_console_format(
|
||||
"[<fg:{$color}>%s</fg>] %s\n",
|
||||
str_pad($flag['colorName'], $name_len),
|
||||
$flag['handle']['fullname']);
|
||||
if ($flag['note']) {
|
||||
$note = phutil_console_wrap($flag['note'], $name_len + 3);
|
||||
echo rtrim($note)."\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Base workflow for Phrequent workflows.
|
||||
*/
|
||||
abstract class ArcanistPhrequentWorkflow extends ArcanistWorkflow {
|
||||
|
||||
protected function printCurrentTracking() {
|
||||
$conduit = $this->getConduit();
|
||||
|
||||
$results = $conduit->callMethodSynchronous(
|
||||
'phrequent.tracking',
|
||||
array());
|
||||
$results = $results['data'];
|
||||
|
||||
if (count($results) === 0) {
|
||||
echo phutil_console_format(
|
||||
"%s\n",
|
||||
pht('Not currently tracking time against any object.'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
$phids_to_lookup = array();
|
||||
foreach ($results as $result) {
|
||||
$phids_to_lookup[] = $result['phid'];
|
||||
}
|
||||
|
||||
$phid_query = $conduit->callMethodSynchronous(
|
||||
'phid.query',
|
||||
array(
|
||||
'phids' => $phids_to_lookup,
|
||||
));
|
||||
|
||||
$phid_map = array();
|
||||
foreach ($phids_to_lookup as $lookup) {
|
||||
if (array_key_exists($lookup, $phid_query)) {
|
||||
$phid_map[$lookup] = $phid_query[$lookup]['fullName'];
|
||||
} else {
|
||||
$phid_map[$lookup] = pht('Unknown Object');
|
||||
}
|
||||
}
|
||||
|
||||
$table = id(new PhutilConsoleTable())
|
||||
->addColumn('type', array('title' => pht('Status')))
|
||||
->addColumn('time', array('title' => pht('Tracked'), 'align' => 'right'))
|
||||
->addColumn('name', array('title' => pht('Name')))
|
||||
->setBorders(false);
|
||||
|
||||
$i = 0;
|
||||
foreach ($results as $result) {
|
||||
if ($i === 0) {
|
||||
$column_type = pht('In Progress');
|
||||
} else {
|
||||
$column_type = pht('Suspended');
|
||||
}
|
||||
|
||||
$table->addRow(array(
|
||||
'type' => '('.$column_type.')',
|
||||
'time' => tsprintf($result['time']),
|
||||
'name' => $phid_map[$result['phid']],
|
||||
));
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
$table->draw();
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Redirects to `arc backout` workflow.
|
||||
*/
|
||||
final class ArcanistRevertWorkflow extends ArcanistWorkflow {
|
||||
|
||||
public function getWorkflowName() {
|
||||
return 'revert';
|
||||
}
|
||||
|
||||
public function getCommandSynopses() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**revert**
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
Please use arc backout instead
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getArguments() {
|
||||
return array(
|
||||
'*' => 'input',
|
||||
);
|
||||
}
|
||||
|
||||
public function getSupportedRevisionControlSystems() {
|
||||
return array('git', 'hg');
|
||||
}
|
||||
|
||||
public function run() {
|
||||
echo pht(
|
||||
'Please use `%s` instead.',
|
||||
'arc backout')."\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Start time tracking on an object.
|
||||
*/
|
||||
final class ArcanistStartWorkflow extends ArcanistPhrequentWorkflow {
|
||||
|
||||
public function getWorkflowName() {
|
||||
return 'start';
|
||||
}
|
||||
|
||||
public function getCommandSynopses() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**start** __object__
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
Start tracking work in Phrequent.
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function requiresConduit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requiresAuthentication() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getArguments() {
|
||||
return array(
|
||||
'*' => 'name',
|
||||
);
|
||||
}
|
||||
|
||||
public function run() {
|
||||
$conduit = $this->getConduit();
|
||||
|
||||
$started_phids = array();
|
||||
$short_name = $this->getArgument('name');
|
||||
|
||||
foreach ($short_name as $object_name) {
|
||||
$object_lookup = $conduit->callMethodSynchronous(
|
||||
'phid.lookup',
|
||||
array(
|
||||
'names' => array($object_name),
|
||||
));
|
||||
|
||||
if (!array_key_exists($object_name, $object_lookup)) {
|
||||
echo phutil_console_format(
|
||||
"%s\n",
|
||||
pht("No such object '%s' found.", $object_name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
$object_phid = $object_lookup[$object_name]['phid'];
|
||||
|
||||
$started_phids[] = $conduit->callMethodSynchronous(
|
||||
'phrequent.push',
|
||||
array(
|
||||
'objectPHID' => $object_phid,
|
||||
));
|
||||
}
|
||||
|
||||
$phid_query = $conduit->callMethodSynchronous(
|
||||
'phid.query',
|
||||
array(
|
||||
'phids' => $started_phids,
|
||||
));
|
||||
|
||||
echo phutil_console_format(
|
||||
"%s: %s\n\n",
|
||||
pht('Started'),
|
||||
implode(', ', ipull($phid_query, 'fullName')));
|
||||
$this->printCurrentTracking();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Stop time tracking on an object.
|
||||
*/
|
||||
final class ArcanistStopWorkflow extends ArcanistPhrequentWorkflow {
|
||||
|
||||
public function getWorkflowName() {
|
||||
return 'stop';
|
||||
}
|
||||
|
||||
public function getCommandSynopses() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**stop** [--note __note__] [__objects__]
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
Stop tracking work in Phrequent.
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function requiresConduit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requiresAuthentication() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getArguments() {
|
||||
return array(
|
||||
'note' => array(
|
||||
'param' => 'note',
|
||||
'help' => pht('A note to attach to the tracked time.'),
|
||||
),
|
||||
'*' => 'name',
|
||||
);
|
||||
}
|
||||
|
||||
public function run() {
|
||||
$conduit = $this->getConduit();
|
||||
$names = $this->getArgument('name');
|
||||
|
||||
$object_lookup = $conduit->callMethodSynchronous(
|
||||
'phid.lookup',
|
||||
array(
|
||||
'names' => $names,
|
||||
));
|
||||
|
||||
foreach ($names as $object_name) {
|
||||
if (!array_key_exists($object_name, $object_lookup)) {
|
||||
throw new ArcanistUsageException(
|
||||
pht("No such object '%s' found.", $object_name));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($names) === 0) {
|
||||
// Implicit stop; add an entry so the loop will call
|
||||
// `phrequent.pop` with a null `objectPHID`.
|
||||
$object_lookup[] = array('phid' => null);
|
||||
}
|
||||
|
||||
$stopped_phids = array();
|
||||
foreach ($object_lookup as $ref) {
|
||||
$object_phid = $ref['phid'];
|
||||
|
||||
$stopped_phid = $conduit->callMethodSynchronous(
|
||||
'phrequent.pop',
|
||||
array(
|
||||
'objectPHID' => $object_phid,
|
||||
'note' => $this->getArgument('note'),
|
||||
));
|
||||
if ($stopped_phid !== null) {
|
||||
$stopped_phids[] = $stopped_phid;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($stopped_phids) === 0) {
|
||||
if (count($names) === 0) {
|
||||
echo phutil_console_format(
|
||||
"%s\n",
|
||||
pht('Not currently tracking time against any object.'));
|
||||
} else {
|
||||
echo phutil_console_format(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Not currently tracking time against %s.',
|
||||
implode(', ', ipull($object_lookup, 'fullName'))));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
$phid_query = $conduit->callMethodSynchronous(
|
||||
'phid.query',
|
||||
array(
|
||||
'phids' => $stopped_phids,
|
||||
));
|
||||
|
||||
echo phutil_console_format(
|
||||
"%s %s\n\n",
|
||||
pht('Stopped:'),
|
||||
implode(', ', ipull($phid_query, 'fullName')));
|
||||
$this->printCurrentTracking();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Show time being tracked in Phrequent.
|
||||
*/
|
||||
final class ArcanistTimeWorkflow extends ArcanistPhrequentWorkflow {
|
||||
|
||||
public function getWorkflowName() {
|
||||
return 'time';
|
||||
}
|
||||
|
||||
public function getCommandSynopses() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
**time**
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function getCommandHelp() {
|
||||
return phutil_console_format(<<<EOTEXT
|
||||
Show what you're currently tracking in Phrequent.
|
||||
EOTEXT
|
||||
);
|
||||
}
|
||||
|
||||
public function requiresConduit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requiresAuthentication() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function run() {
|
||||
$this->printCurrentTracking();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue