Changeset View
Changeset View
Standalone View
Standalone View
src/workflow/ArcanistBackoutWorkflow.php
| <?php | <?php | ||||
| /** | /** | ||||
| * Runs git revert and assigns hi pri task to original author | * Runs git revert and assigns a high priority task to original author. | ||||
| * @group workflow | |||||
| */ | */ | ||||
| final class ArcanistBackoutWorkflow extends ArcanistBaseWorkflow { | final class ArcanistBackoutWorkflow extends ArcanistBaseWorkflow { | ||||
| private $console; | private $console; | ||||
| private $conduit; | private $conduit; | ||||
| private $revision; | private $revision; | ||||
| public function getWorkflowName() { | public function getWorkflowName() { | ||||
| return 'backout'; | return 'backout'; | ||||
| } | } | ||||
| Show All 28 Lines | EOTEXT | ||||
| public function requiresRepositoryAPI() { | public function requiresRepositoryAPI() { | ||||
| return true; | return true; | ||||
| } | } | ||||
| public function requiresAuthentication() { | public function requiresAuthentication() { | ||||
| return true; | return true; | ||||
| } | } | ||||
| // Given a differential revision ID, fetches the commit ID | /** | ||||
| * Given a differential revision ID, fetches the commit ID. | |||||
| */ | |||||
| private function getCommitIDFromRevisionID($revision_id) { | private function getCommitIDFromRevisionID($revision_id) { | ||||
| $conduit = $this->getConduit(); | $conduit = $this->getConduit(); | ||||
| $revisions = $conduit->callMethodSynchronous( | $revisions = $conduit->callMethodSynchronous( | ||||
| 'differential.query', | 'differential.query', | ||||
| array( | array( | ||||
| 'ids' => array($revision_id), | 'ids' => array($revision_id), | ||||
| )); | )); | ||||
| if (!$revisions) { | if (!$revisions) { | ||||
| Show All 15 Lines | $commit = $conduit->callMethodSynchronous( | ||||
| 'phid.query', | 'phid.query', | ||||
| array( | array( | ||||
| 'phids' => array($commit_phid), | 'phids' => array($commit_phid), | ||||
| )); | )); | ||||
| $commit_id = $commit[$commit_phid]['name']; | $commit_id = $commit[$commit_phid]['name']; | ||||
| return $commit_id; | return $commit_id; | ||||
| } | } | ||||
| // Fetches an array of commit info provided a Commit_id | /** | ||||
| // in the form of rE123456 (not local commit hash) | * Fetches an array of commit info provided a Commit_id in the form of | ||||
| * rE123456 (not local commit hash). | |||||
| */ | |||||
| private function getDiffusionCommit($commit_id) { | private function getDiffusionCommit($commit_id) { | ||||
| $result = $this->getConduit()->callMethodSynchronous( | $result = $this->getConduit()->callMethodSynchronous( | ||||
| 'diffusion.getcommits', | 'diffusion.getcommits', | ||||
| array( | array( | ||||
| 'commits' => array($commit_id), | 'commits' => array($commit_id), | ||||
| )); | )); | ||||
| $commit = $result[$commit_id]; | $commit = $result[$commit_id]; | ||||
| // This commit was not found in Diffusion | // This commit was not found in Diffusion | ||||
| if (array_key_exists('error', $commit)) { | if (array_key_exists('error', $commit)) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return $commit; | return $commit; | ||||
| } | } | ||||
| // Retrieves default template from differential and prefills info | /** | ||||
| * Retrieves default template from differential and pre-fills info. | |||||
| */ | |||||
| private function buildCommitMessage($commit_hash) { | private function buildCommitMessage($commit_hash) { | ||||
| $conduit = $this->getConduit(); | $conduit = $this->getConduit(); | ||||
| $repository_api = $this->getRepositoryAPI(); | $repository_api = $this->getRepositoryAPI(); | ||||
| $summary = $repository_api->getBackoutMessage($commit_hash); | $summary = $repository_api->getBackoutMessage($commit_hash); | ||||
| $fields = array('summary' => $summary, | $fields = array( | ||||
| 'summary' => $summary, | |||||
| 'testPlan' => 'revert-hammer', | 'testPlan' => 'revert-hammer', | ||||
| ); | ); | ||||
| $template = $conduit->callMethodSynchronous( | $template = $conduit->callMethodSynchronous( | ||||
| 'differential.getcommitmessage', | 'differential.getcommitmessage', | ||||
| array( | array( | ||||
| 'revision_id' => null, | 'revision_id' => null, | ||||
| 'edit' => 'create', | 'edit' => 'create', | ||||
| 'fields' => $fields | 'fields' => $fields | ||||
| )); | )); | ||||
| $template = $this->newInteractiveEditor($template) | $template = $this->newInteractiveEditor($template) | ||||
| ->setName('new-commit') | ->setName('new-commit') | ||||
| ->editInteractively(); | ->editInteractively(); | ||||
| return $template; | return $template; | ||||
| } | } | ||||
| // Performs the backout/revert of a revision and creates a commit | /** | ||||
| * Performs the backout/revert of a revision and creates a commit. | |||||
| */ | |||||
| public function run() { | public function run() { | ||||
| $console = PhutilConsole::getConsole(); | $console = PhutilConsole::getConsole(); | ||||
| $conduit = $this->getConduit(); | $conduit = $this->getConduit(); | ||||
| $repository_api = $this->getRepositoryAPI(); | $repository_api = $this->getRepositoryAPI(); | ||||
| $is_git_svn = $repository_api instanceof ArcanistGitAPI && | $is_git_svn = $repository_api instanceof ArcanistGitAPI && | ||||
| $repository_api->isGitSubversionRepo(); | $repository_api->isGitSubversionRepo(); | ||||
| $is_hg_svn = $repository_api instanceof ArcanistMercurialAPI && | $is_hg_svn = $repository_api instanceof ArcanistMercurialAPI && | ||||
| $repository_api->isHgSubversionRepo(); | $repository_api->isHgSubversionRepo(); | ||||
| $revision_id = null; | $revision_id = null; | ||||
| if (!($repository_api instanceof ArcanistGitAPI) && | if (!($repository_api instanceof ArcanistGitAPI) && | ||||
| !($repository_api instanceof ArcanistMercurialAPI)) { | !($repository_api instanceof ArcanistMercurialAPI)) { | ||||
| throw new ArcanistUsageException( | throw new ArcanistUsageException( | ||||
| 'Backout currently only supports Git and Mercurial' | 'Backout currently only supports Git and Mercurial' | ||||
| ); | ); | ||||
| } | } | ||||
| Show All 18 Lines | if (preg_match('/^D(\d+)$/i', $input[0], $matches)) { | ||||
| $commit_hash = $repository_api-> | $commit_hash = $repository_api-> | ||||
| getHashFromFromSVNRevisionNumber($commit_hash); | getHashFromFromSVNRevisionNumber($commit_hash); | ||||
| } | } | ||||
| } else { | } else { | ||||
| // Assume input is a commit hash | // Assume input is a commit hash | ||||
| $commit_hash = $input[0]; | $commit_hash = $input[0]; | ||||
| } | } | ||||
| if (!$repository_api->hasLocalCommit($commit_hash)) { | if (!$repository_api->hasLocalCommit($commit_hash)) { | ||||
| throw new ArcanistUsageException('Invalid commit provided or does not'. | throw new ArcanistUsageException( | ||||
| 'exist in the working copy!'); | 'Invalid commit provided or does not exist in the working copy!'); | ||||
| } | } | ||||
| // Run 'backout'. | // Run 'backout'. | ||||
| $subject = $repository_api->getCommitSummary($commit_hash); | $subject = $repository_api->getCommitSummary($commit_hash); | ||||
| $console->writeOut("Backing out commit {$commit_hash} {$subject} \n"); | $console->writeOut("Backing out commit {$commit_hash} {$subject} \n"); | ||||
| $repository_api->backoutCommit($commit_hash); | $repository_api->backoutCommit($commit_hash); | ||||
| // Create commit message and execute the commit | // Create commit message and execute the commit | ||||
| $message = $this->buildCommitMessage($commit_hash); | $message = $this->buildCommitMessage($commit_hash); | ||||
| $repository_api->doCommit($message); | $repository_api->doCommit($message); | ||||
| $console->writeOut("Double-check the commit and push when ready\n"); | $console->writeOut("Double-check the commit and push when ready\n"); | ||||
| } | } | ||||
| } | } | ||||